mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-02-21 16:43:35 +00:00
Take componentMask and scissor into account when clearing framebuffer attachments
This commit is contained in:
parent
746eded2cf
commit
80d72504d4
7 changed files with 183 additions and 25 deletions
|
@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||
{
|
||||
public const int ShaderStateIndex = 16;
|
||||
public const int RasterizerStateIndex = 15;
|
||||
public const int ScissorStateIndex = 17;
|
||||
public const int ScissorStateIndex = 18;
|
||||
public const int VertexBufferStateIndex = 0;
|
||||
public const int PrimitiveRestartStateIndex = 12;
|
||||
|
||||
|
|
|
@ -121,14 +121,29 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
AttachmentsCount = count;
|
||||
}
|
||||
|
||||
public Auto<DisposableImageView> GetAttachment(int index)
|
||||
{
|
||||
if ((uint)index >= _attachments.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _attachments[index];
|
||||
}
|
||||
|
||||
private static bool IsValidTextureView(ITexture texture)
|
||||
{
|
||||
return texture is TextureView view && view.Valid;
|
||||
}
|
||||
|
||||
public ClearRect GetClearRect()
|
||||
public ClearRect GetClearRect(Rectangle<int> scissor)
|
||||
{
|
||||
return new ClearRect(new Rect2D(null, new Extent2D(Width, Height)), 0, Layers);
|
||||
int x = scissor.X;
|
||||
int y = scissor.Y;
|
||||
int width = Math.Min((int)Width - scissor.X, scissor.Width);
|
||||
int height = Math.Min((int)Height - scissor.Y, scissor.Height);
|
||||
|
||||
return new ClearRect(new Rect2D(new Offset2D(x, y), new Extent2D((uint)width, (uint)height)), 0, Layers);
|
||||
}
|
||||
|
||||
public unsafe Auto<DisposableFramebuffer> Create(Vk api, CommandBufferScoped cbs, Auto<DisposableRenderPass> renderPass)
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
{
|
||||
class HelperShader : IDisposable
|
||||
{
|
||||
private const string VertexShaderSource = @"#version 450 core
|
||||
private const string ColorBlitVertexShaderSource = @"#version 450 core
|
||||
|
||||
layout (std140, binding = 1) uniform tex_coord_in
|
||||
{
|
||||
|
@ -41,7 +41,7 @@ void main()
|
|||
colour = texture(tex, tex_coord);
|
||||
}";
|
||||
|
||||
private const string ClearAlphaFragmentShaderSource = @"#version 450 core
|
||||
private const string ColorBlitClearAlphaFragmentShaderSource = @"#version 450 core
|
||||
|
||||
layout (binding = 32, set = 2) uniform sampler2D tex;
|
||||
|
||||
|
@ -53,15 +53,47 @@ void main()
|
|||
colour = vec4(texture(tex, tex_coord).rgb, 1.0f);
|
||||
}";
|
||||
|
||||
private readonly PipelineBlit _pipeline;
|
||||
private const string ColorClearVertexShaderSource = @"#version 450 core
|
||||
|
||||
layout (std140, binding = 1) uniform clear_colour_in
|
||||
{
|
||||
vec4 clear_colour_in_data;
|
||||
};
|
||||
|
||||
layout (location = 0) out vec4 clear_colour;
|
||||
|
||||
void main()
|
||||
{
|
||||
int low = gl_VertexIndex & 1;
|
||||
int high = gl_VertexIndex >> 1;
|
||||
clear_colour = clear_colour_in_data;
|
||||
gl_Position.x = (float(low) - 0.5f) * 2.0f;
|
||||
gl_Position.y = (float(high) - 0.5f) * 2.0f;
|
||||
gl_Position.z = 0.0f;
|
||||
gl_Position.w = 1.0f;
|
||||
}";
|
||||
|
||||
private const string ColorClearFragmentShaderSource = @"#version 450 core
|
||||
|
||||
layout (location = 0) in vec4 clear_colour;
|
||||
layout (location = 0) out vec4 colour;
|
||||
|
||||
void main()
|
||||
{
|
||||
colour = clear_colour;
|
||||
}";
|
||||
|
||||
|
||||
private readonly PipelineHelperShader _pipeline;
|
||||
private readonly ISampler _samplerLinear;
|
||||
private readonly ISampler _samplerNearest;
|
||||
private readonly IProgram _programColorBlit;
|
||||
private readonly IProgram _programClearAlpha;
|
||||
private readonly IProgram _programColorBlitClearAlpha;
|
||||
private readonly IProgram _programColorClear;
|
||||
|
||||
public HelperShader(VulkanGraphicsDevice gd, Device device)
|
||||
{
|
||||
_pipeline = new PipelineBlit(gd, device);
|
||||
_pipeline = new PipelineHelperShader(gd, device);
|
||||
|
||||
static GAL.SamplerCreateInfo GetSamplerCreateInfo(MinFilter minFilter, MagFilter magFilter)
|
||||
{
|
||||
|
@ -100,12 +132,25 @@ void main()
|
|||
Array.Empty<int>(),
|
||||
Array.Empty<int>());
|
||||
|
||||
var vertexShader = gd.CompileShader(ShaderStage.Vertex, vertexBindings, VertexShaderSource);
|
||||
var fragmentShaderColorBlit = gd.CompileShader(ShaderStage.Fragment, fragmentBindings, ColorBlitFragmentShaderSource);
|
||||
var fragmentShaderClearAlpha = gd.CompileShader(ShaderStage.Fragment, fragmentBindings, ClearAlphaFragmentShaderSource);
|
||||
var colorBlitVertexShader = gd.CompileShader(ShaderStage.Vertex, vertexBindings, ColorBlitVertexShaderSource);
|
||||
var colorBlitFragmentShader = gd.CompileShader(ShaderStage.Fragment, fragmentBindings, ColorBlitFragmentShaderSource);
|
||||
var colorBlitClearAlphaFragmentShader = gd.CompileShader(ShaderStage.Fragment, fragmentBindings, ColorBlitClearAlphaFragmentShaderSource);
|
||||
|
||||
_programColorBlit = gd.CreateProgram(new[] { vertexShader, fragmentShaderColorBlit }, new ShaderInfo(-1));
|
||||
_programClearAlpha = gd.CreateProgram(new[] { vertexShader, fragmentShaderClearAlpha }, new ShaderInfo(-1));
|
||||
_programColorBlit = gd.CreateProgram(new[] { colorBlitVertexShader, colorBlitFragmentShader }, new ShaderInfo(-1));
|
||||
_programColorBlitClearAlpha = gd.CreateProgram(new[] { colorBlitVertexShader, colorBlitClearAlphaFragmentShader }, new ShaderInfo(-1));
|
||||
|
||||
var fragmentBindings2 = new ShaderBindings(
|
||||
Array.Empty<int>(),
|
||||
Array.Empty<int>(),
|
||||
Array.Empty<int>(),
|
||||
Array.Empty<int>(),
|
||||
Array.Empty<int>(),
|
||||
Array.Empty<int>());
|
||||
|
||||
var colorClearVertexShader = gd.CompileShader(ShaderStage.Vertex, vertexBindings, ColorClearVertexShaderSource);
|
||||
var colorClearFragmentShader = gd.CompileShader(ShaderStage.Fragment, fragmentBindings2, ColorClearFragmentShaderSource);
|
||||
|
||||
_programColorClear = gd.CreateProgram(new[] { colorClearVertexShader, colorClearFragmentShader }, new ShaderInfo(-1));
|
||||
}
|
||||
|
||||
public void Blit(
|
||||
|
@ -200,15 +245,70 @@ void main()
|
|||
|
||||
scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight);
|
||||
|
||||
_pipeline.SetProgram(clearAlpha ? _programClearAlpha : _programColorBlit);
|
||||
_pipeline.SetProgram(clearAlpha ? _programColorBlitClearAlpha : _programColorBlit);
|
||||
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat);
|
||||
_pipeline.SetRenderTargetColorMasks(new uint[] { 0xf });
|
||||
_pipeline.SetScissors(scissors);
|
||||
|
||||
if (clearAlpha)
|
||||
{
|
||||
_pipeline.ClearRenderTargetColor(0, 0xf, new ColorF(0f, 0f, 0f, 1f));
|
||||
_pipeline.ClearRenderTargetColor(0, new ColorF(0f, 0f, 0f, 1f));
|
||||
}
|
||||
|
||||
_pipeline.SetViewports(0, viewports);
|
||||
_pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
|
||||
_pipeline.Draw(4, 1, 0, 0);
|
||||
_pipeline.Finish();
|
||||
|
||||
gd.BufferManager.Delete(bufferHandle);
|
||||
}
|
||||
|
||||
public void Clear(
|
||||
VulkanGraphicsDevice gd,
|
||||
Auto<DisposableImageView> dst,
|
||||
ReadOnlySpan<float> clearColor,
|
||||
uint componentMask,
|
||||
int dstWidth,
|
||||
int dstHeight,
|
||||
VkFormat dstFormat,
|
||||
Rectangle<int> scissor)
|
||||
{
|
||||
gd.FlushAllCommands();
|
||||
|
||||
using var cbs = gd.CommandBufferPool.Rent();
|
||||
|
||||
_pipeline.SetCommandBuffer(cbs);
|
||||
|
||||
const int ClearColorBufferSize = 16;
|
||||
|
||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ClearColorBufferSize, false);
|
||||
|
||||
gd.BufferManager.SetData<float>(bufferHandle, 0, clearColor);
|
||||
|
||||
Span<BufferRange> bufferRanges = stackalloc BufferRange[1];
|
||||
|
||||
bufferRanges[0] = new BufferRange(bufferHandle, 0, ClearColorBufferSize);
|
||||
|
||||
_pipeline.SetUniformBuffers(1, bufferRanges);
|
||||
|
||||
Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
|
||||
|
||||
viewports[0] = new GAL.Viewport(
|
||||
new Rectangle<float>(0, 0, dstWidth, dstHeight),
|
||||
ViewportSwizzle.PositiveX,
|
||||
ViewportSwizzle.PositiveY,
|
||||
ViewportSwizzle.PositiveZ,
|
||||
ViewportSwizzle.PositiveW,
|
||||
0f,
|
||||
1f);
|
||||
|
||||
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
|
||||
|
||||
scissors[0] = scissor;
|
||||
|
||||
_pipeline.SetProgram(_programColorClear);
|
||||
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat);
|
||||
_pipeline.SetRenderTargetColorMasks(new uint[] { componentMask });
|
||||
_pipeline.SetViewports(0, viewports);
|
||||
_pipeline.SetScissors(scissors);
|
||||
_pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
|
||||
|
@ -335,7 +435,7 @@ void main()
|
|||
{
|
||||
if (disposing)
|
||||
{
|
||||
_programClearAlpha.Dispose();
|
||||
_programColorBlitClearAlpha.Dispose();
|
||||
_programColorBlit.Dispose();
|
||||
_samplerNearest.Dispose();
|
||||
_samplerLinear.Dispose();
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
private BufferState _indexBuffer;
|
||||
private readonly BufferState[] _transformFeedbackBuffers;
|
||||
private readonly BufferState[] _vertexBuffers;
|
||||
protected Rectangle<int> ClearScissor;
|
||||
|
||||
public SupportBufferUpdater SupportBufferUpdater;
|
||||
|
||||
|
@ -88,6 +89,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_vertexBuffers[0] = new BufferState(emptyVb.GetBuffer(), 0, EmptyVbSize, 0UL);
|
||||
_needsVertexBuffersRebind = true;
|
||||
|
||||
ClearScissor = new Rectangle<int>(0, 0, 0xffff, 0xffff);
|
||||
|
||||
var defaultScale = new Vector4<float> { X = 1f, Y = 0f, Z = 0f, W = 0f };
|
||||
new Span<Vector4<float>>(_renderScale).Fill(defaultScale);
|
||||
|
||||
|
@ -140,10 +143,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
Gd.Api.CmdFillBuffer(CommandBuffer, dst, (ulong)offset, (ulong)size, value);
|
||||
}
|
||||
|
||||
public unsafe void ClearRenderTargetColor(int index, uint componentMask, ColorF color)
|
||||
public unsafe void ClearRenderTargetColor(int index, ColorF color)
|
||||
{
|
||||
// TODO: Use componentMask
|
||||
|
||||
if (_framebuffer == null)
|
||||
{
|
||||
return;
|
||||
|
@ -158,7 +159,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
var clearValue = new ClearValue(new ClearColorValue(color.Red, color.Green, color.Blue, color.Alpha));
|
||||
var attachment = new ClearAttachment(ImageAspectFlags.ImageAspectColorBit, (uint)index, clearValue);
|
||||
var clearRect = FramebufferParams?.GetClearRect() ?? default;
|
||||
var clearRect = FramebufferParams?.GetClearRect(ClearScissor) ?? default;
|
||||
|
||||
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
||||
}
|
||||
|
@ -188,7 +189,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
}
|
||||
|
||||
var attachment = new ClearAttachment(flags, 0, clearValue);
|
||||
var clearRect = FramebufferParams?.GetClearRect() ?? default;
|
||||
var clearRect = FramebufferParams?.GetClearRect(ClearScissor) ?? default;
|
||||
|
||||
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
||||
}
|
||||
|
@ -618,6 +619,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
public void SetScissors(ReadOnlySpan<Rectangle<int>> regions)
|
||||
{
|
||||
int count = Math.Min(Constants.MaxViewports, regions.Length);
|
||||
if (count > 0)
|
||||
{
|
||||
ClearScissor = regions[0];
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
|
@ -1047,7 +1052,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
private void RecreatePipelineIfNeeded(PipelineBindPoint pbp)
|
||||
{
|
||||
// Take the opportunity to process any pending work requested by other threads.
|
||||
_dynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
||||
|
||||
// Commit changes to the support buffer before drawing.
|
||||
|
|
|
@ -183,6 +183,45 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
return layouts;
|
||||
}
|
||||
|
||||
public void ClearRenderTargetColor(int index, uint componentMask, ColorF color)
|
||||
{
|
||||
if (FramebufferParams == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (componentMask != 0xf)
|
||||
{
|
||||
// We can't use CmdClearAttachments if the clear has a custom scissor or is not writing all components,
|
||||
// because on Vulkan, the pipeline state does not affect clears.
|
||||
var dstTexture = FramebufferParams.GetAttachment(index);
|
||||
if (dstTexture == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Span<float> clearColor = stackalloc float[4];
|
||||
clearColor[0] = color.Red;
|
||||
clearColor[1] = color.Green;
|
||||
clearColor[2] = color.Blue;
|
||||
clearColor[3] = color.Alpha;
|
||||
|
||||
Gd.HelperShader.Clear(
|
||||
Gd,
|
||||
dstTexture,
|
||||
clearColor,
|
||||
componentMask,
|
||||
(int)FramebufferParams.Width,
|
||||
(int)FramebufferParams.Height,
|
||||
FramebufferParams.AttachmentFormats[index],
|
||||
ClearScissor);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearRenderTargetColor(index, color);
|
||||
}
|
||||
}
|
||||
|
||||
public void EndHostConditionalRendering()
|
||||
{
|
||||
if (Gd.Capabilities.SupportsConditionalRendering)
|
||||
|
|
|
@ -3,9 +3,9 @@ using VkFormat = Silk.NET.Vulkan.Format;
|
|||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
class PipelineBlit : PipelineBase
|
||||
class PipelineHelperShader : PipelineBase
|
||||
{
|
||||
public PipelineBlit(VulkanGraphicsDevice gd, Device device) : base(gd, device)
|
||||
public PipelineHelperShader(VulkanGraphicsDevice gd, Device device) : base(gd, device)
|
||||
{
|
||||
}
|
||||
|
|
@ -299,7 +299,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
public NativeArray<PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT> StageRequiredSubgroupSizes;
|
||||
public PipelineLayout PipelineLayout;
|
||||
|
||||
public unsafe void Initialize()
|
||||
public void Initialize()
|
||||
{
|
||||
Stages = new NativeArray<PipelineShaderStageCreateInfo>(Constants.MaxShaderStages);
|
||||
StageRequiredSubgroupSizes = new NativeArray<PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT>(Constants.MaxShaderStages);
|
||||
|
|
Loading…
Reference in a new issue