DepthStencil Blits
This commit is contained in:
parent
aa6e87e8a6
commit
3a04d72686
9 changed files with 310 additions and 29 deletions
|
@ -26,6 +26,10 @@ namespace Ryujinx.Graphics.Metal
|
||||||
private readonly List<IProgram> _programsColorClear = new();
|
private readonly List<IProgram> _programsColorClear = new();
|
||||||
private readonly IProgram _programDepthStencilClear;
|
private readonly IProgram _programDepthStencilClear;
|
||||||
private readonly IProgram _programStrideChange;
|
private readonly IProgram _programStrideChange;
|
||||||
|
private readonly IProgram _programDepthBlit;
|
||||||
|
private readonly IProgram _programDepthBlitMs;
|
||||||
|
private readonly IProgram _programStencilBlit;
|
||||||
|
private readonly IProgram _programStencilBlitMs;
|
||||||
|
|
||||||
private readonly EncoderState _helperShaderState = new();
|
private readonly EncoderState _helperShaderState = new();
|
||||||
|
|
||||||
|
@ -53,7 +57,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
_programColorBlitMs = new Program(
|
_programColorBlitMs = new Program(
|
||||||
[
|
[
|
||||||
new ShaderSource(blitMsSource, ShaderStage.Fragment, TargetLanguage.Msl),
|
new ShaderSource(blitMsSource, ShaderStage.Fragment, TargetLanguage.Msl),
|
||||||
new ShaderSource(blitMsSource, ShaderStage.Vertex, TargetLanguage.Msl)
|
new ShaderSource(blitSource, ShaderStage.Vertex, TargetLanguage.Msl)
|
||||||
], blitResourceLayout, device);
|
], blitResourceLayout, device);
|
||||||
|
|
||||||
var colorClearResourceLayout = new ResourceLayoutBuilder()
|
var colorClearResourceLayout = new ResourceLayoutBuilder()
|
||||||
|
@ -87,6 +91,34 @@ namespace Ryujinx.Graphics.Metal
|
||||||
[
|
[
|
||||||
new ShaderSource(strideChangeSource, ShaderStage.Compute, TargetLanguage.Msl)
|
new ShaderSource(strideChangeSource, ShaderStage.Compute, TargetLanguage.Msl)
|
||||||
], strideChangeResourceLayout, device, new ComputeSize(64, 1, 1));
|
], strideChangeResourceLayout, device, new ComputeSize(64, 1, 1));
|
||||||
|
|
||||||
|
var depthBlitSource = ReadMsl("DepthBlit.metal");
|
||||||
|
_programDepthBlit = new Program(
|
||||||
|
[
|
||||||
|
new ShaderSource(depthBlitSource, ShaderStage.Fragment, TargetLanguage.Msl),
|
||||||
|
new ShaderSource(blitSource, ShaderStage.Vertex, TargetLanguage.Msl)
|
||||||
|
], blitResourceLayout, device);
|
||||||
|
|
||||||
|
var depthBlitMsSource = ReadMsl("DepthBlitMs.metal");
|
||||||
|
_programDepthBlitMs = new Program(
|
||||||
|
[
|
||||||
|
new ShaderSource(depthBlitMsSource, ShaderStage.Fragment, TargetLanguage.Msl),
|
||||||
|
new ShaderSource(blitSource, ShaderStage.Vertex, TargetLanguage.Msl)
|
||||||
|
], blitResourceLayout, device);
|
||||||
|
|
||||||
|
var stencilBlitSource = ReadMsl("StencilBlit.metal");
|
||||||
|
_programStencilBlit = new Program(
|
||||||
|
[
|
||||||
|
new ShaderSource(stencilBlitSource, ShaderStage.Fragment, TargetLanguage.Msl),
|
||||||
|
new ShaderSource(blitSource, ShaderStage.Vertex, TargetLanguage.Msl)
|
||||||
|
], blitResourceLayout, device);
|
||||||
|
|
||||||
|
var stencilBlitMsSource = ReadMsl("StencilBlitMs.metal");
|
||||||
|
_programStencilBlitMs = new Program(
|
||||||
|
[
|
||||||
|
new ShaderSource(stencilBlitMsSource, ShaderStage.Fragment, TargetLanguage.Msl),
|
||||||
|
new ShaderSource(blitSource, ShaderStage.Vertex, TargetLanguage.Msl)
|
||||||
|
], blitResourceLayout, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ReadMsl(string fileName)
|
private static string ReadMsl(string fileName)
|
||||||
|
@ -193,6 +225,155 @@ namespace Ryujinx.Graphics.Metal
|
||||||
_pipeline.SwapState(null);
|
_pipeline.SwapState(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public unsafe void BlitDepthStencil(
|
||||||
|
CommandBufferScoped cbs,
|
||||||
|
Texture src,
|
||||||
|
Texture dst,
|
||||||
|
Extents2D srcRegion,
|
||||||
|
Extents2D dstRegion)
|
||||||
|
{
|
||||||
|
_pipeline.SwapState(_helperShaderState);
|
||||||
|
|
||||||
|
const int RegionBufferSize = 16;
|
||||||
|
|
||||||
|
Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
|
||||||
|
|
||||||
|
region[0] = srcRegion.X1 / (float)src.Width;
|
||||||
|
region[1] = srcRegion.X2 / (float)src.Width;
|
||||||
|
region[2] = srcRegion.Y1 / (float)src.Height;
|
||||||
|
region[3] = srcRegion.Y2 / (float)src.Height;
|
||||||
|
|
||||||
|
if (dstRegion.X1 > dstRegion.X2)
|
||||||
|
{
|
||||||
|
(region[0], region[1]) = (region[1], region[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dstRegion.Y1 > dstRegion.Y2)
|
||||||
|
{
|
||||||
|
(region[2], region[3]) = (region[3], region[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
using var buffer = _renderer.BufferManager.ReserveOrCreate(cbs, RegionBufferSize);
|
||||||
|
buffer.Holder.SetDataUnchecked<float>(buffer.Offset, region);
|
||||||
|
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
|
||||||
|
|
||||||
|
Span<Viewport> viewports = stackalloc Viewport[16];
|
||||||
|
|
||||||
|
var rect = new Rectangle<float>(
|
||||||
|
MathF.Min(dstRegion.X1, dstRegion.X2),
|
||||||
|
MathF.Min(dstRegion.Y1, dstRegion.Y2),
|
||||||
|
MathF.Abs(dstRegion.X2 - dstRegion.X1),
|
||||||
|
MathF.Abs(dstRegion.Y2 - dstRegion.Y1));
|
||||||
|
|
||||||
|
viewports[0] = new Viewport(
|
||||||
|
rect,
|
||||||
|
ViewportSwizzle.PositiveX,
|
||||||
|
ViewportSwizzle.PositiveY,
|
||||||
|
ViewportSwizzle.PositiveZ,
|
||||||
|
ViewportSwizzle.PositiveW,
|
||||||
|
0f,
|
||||||
|
1f);
|
||||||
|
|
||||||
|
int dstWidth = dst.Width;
|
||||||
|
int dstHeight = dst.Height;
|
||||||
|
|
||||||
|
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[16];
|
||||||
|
|
||||||
|
scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight);
|
||||||
|
|
||||||
|
_pipeline.SetRenderTargets([], dst);
|
||||||
|
_pipeline.SetScissors(scissors);
|
||||||
|
_pipeline.SetViewports(viewports);
|
||||||
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||||
|
|
||||||
|
if (src.Info.Format is
|
||||||
|
Format.D16Unorm or
|
||||||
|
Format.D32Float or
|
||||||
|
Format.X8UintD24Unorm or
|
||||||
|
Format.D24UnormS8Uint or
|
||||||
|
Format.D32FloatS8Uint or
|
||||||
|
Format.S8UintD24Unorm)
|
||||||
|
{
|
||||||
|
var depthTexture = CreateDepthOrStencilView(src, DepthStencilMode.Depth);
|
||||||
|
|
||||||
|
BlitDepthStencilDraw(depthTexture, isDepth: true);
|
||||||
|
|
||||||
|
if (depthTexture != src)
|
||||||
|
{
|
||||||
|
depthTexture.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src.Info.Format is
|
||||||
|
Format.S8Uint or
|
||||||
|
Format.D24UnormS8Uint or
|
||||||
|
Format.D32FloatS8Uint or
|
||||||
|
Format.S8UintD24Unorm)
|
||||||
|
{
|
||||||
|
var stencilTexture = CreateDepthOrStencilView(src, DepthStencilMode.Stencil);
|
||||||
|
|
||||||
|
BlitDepthStencilDraw(stencilTexture, isDepth: false);
|
||||||
|
|
||||||
|
if (stencilTexture != src)
|
||||||
|
{
|
||||||
|
stencilTexture.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore previous state
|
||||||
|
_pipeline.SwapState(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Texture CreateDepthOrStencilView(Texture depthStencilTexture, DepthStencilMode depthStencilMode)
|
||||||
|
{
|
||||||
|
if (depthStencilTexture.Info.DepthStencilMode == depthStencilMode)
|
||||||
|
{
|
||||||
|
return depthStencilTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Texture)depthStencilTexture.CreateView(new TextureCreateInfo(
|
||||||
|
depthStencilTexture.Info.Width,
|
||||||
|
depthStencilTexture.Info.Height,
|
||||||
|
depthStencilTexture.Info.Depth,
|
||||||
|
depthStencilTexture.Info.Levels,
|
||||||
|
depthStencilTexture.Info.Samples,
|
||||||
|
depthStencilTexture.Info.BlockWidth,
|
||||||
|
depthStencilTexture.Info.BlockHeight,
|
||||||
|
depthStencilTexture.Info.BytesPerPixel,
|
||||||
|
depthStencilTexture.Info.Format,
|
||||||
|
depthStencilMode,
|
||||||
|
depthStencilTexture.Info.Target,
|
||||||
|
SwizzleComponent.Red,
|
||||||
|
SwizzleComponent.Green,
|
||||||
|
SwizzleComponent.Blue,
|
||||||
|
SwizzleComponent.Alpha), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BlitDepthStencilDraw(Texture src, bool isDepth)
|
||||||
|
{
|
||||||
|
if (isDepth)
|
||||||
|
{
|
||||||
|
_pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit);
|
||||||
|
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programStencilBlitMs : _programStencilBlit);
|
||||||
|
_pipeline.SetStencilTest(CreateStencilTestDescriptor(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
_pipeline.Draw(4, 1, 0, 0);
|
||||||
|
|
||||||
|
if (isDepth)
|
||||||
|
{
|
||||||
|
_pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pipeline.SetStencilTest(CreateStencilTestDescriptor(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public unsafe void DrawTexture(
|
public unsafe void DrawTexture(
|
||||||
ITexture src,
|
ITexture src,
|
||||||
ISampler srcSampler,
|
ISampler srcSampler,
|
||||||
|
|
|
@ -197,10 +197,18 @@ namespace Ryujinx.Graphics.Metal
|
||||||
Texture dst,
|
Texture dst,
|
||||||
Extents2D srcRegion,
|
Extents2D srcRegion,
|
||||||
Extents2D dstRegion,
|
Extents2D dstRegion,
|
||||||
|
bool isDepthOrStencil,
|
||||||
bool linearFilter)
|
bool linearFilter)
|
||||||
|
{
|
||||||
|
if (isDepthOrStencil)
|
||||||
|
{
|
||||||
|
_renderer.HelperShader.BlitDepthStencil(Cbs, src, dst, srcRegion, dstRegion);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
_renderer.HelperShader.BlitColor(Cbs, src, dst, srcRegion, dstRegion, linearFilter);
|
_renderer.HelperShader.BlitColor(Cbs, src, dst, srcRegion, dstRegion, linearFilter);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Barrier()
|
public void Barrier()
|
||||||
{
|
{
|
||||||
|
@ -258,10 +266,8 @@ namespace Ryujinx.Graphics.Metal
|
||||||
{
|
{
|
||||||
var depthStencil = _encoderStateManager.DepthStencil;
|
var depthStencil = _encoderStateManager.DepthStencil;
|
||||||
|
|
||||||
// TODO: Remove workaround for Wonder which has an invalid texture due to unsupported format
|
|
||||||
if (depthStencil == null)
|
if (depthStencil == null)
|
||||||
{
|
{
|
||||||
Logger.Warning?.PrintMsg(LogClass.Gpu, "Attempted to clear invalid depth stencil!");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,10 @@
|
||||||
<EmbeddedResource Include="Shaders\ChangeBufferStride.metal" />
|
<EmbeddedResource Include="Shaders\ChangeBufferStride.metal" />
|
||||||
<EmbeddedResource Include="Shaders\ColorClear.metal" />
|
<EmbeddedResource Include="Shaders\ColorClear.metal" />
|
||||||
<EmbeddedResource Include="Shaders\DepthStencilClear.metal" />
|
<EmbeddedResource Include="Shaders\DepthStencilClear.metal" />
|
||||||
|
<EmbeddedResource Include="Shaders\DepthBlit.metal" />
|
||||||
|
<EmbeddedResource Include="Shaders\DepthBlitMs.metal" />
|
||||||
|
<EmbeddedResource Include="Shaders\StencilBlit.metal" />
|
||||||
|
<EmbeddedResource Include="Shaders\StencilBlitMs.metal" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -7,35 +7,11 @@ struct CopyVertexOut {
|
||||||
float2 uv;
|
float2 uv;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TexCoords {
|
|
||||||
float data[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ConstantBuffers {
|
|
||||||
constant TexCoords* tex_coord;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Textures
|
struct Textures
|
||||||
{
|
{
|
||||||
texture2d_ms<float, access::read> texture;
|
texture2d_ms<float, access::read> texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
vertex CopyVertexOut vertexMain(uint vid [[vertex_id]],
|
|
||||||
constant ConstantBuffers &constant_buffers [[buffer(20)]]) {
|
|
||||||
CopyVertexOut out;
|
|
||||||
|
|
||||||
int low = vid & 1;
|
|
||||||
int high = vid >> 1;
|
|
||||||
out.uv.x = constant_buffers.tex_coord->data[low];
|
|
||||||
out.uv.y = constant_buffers.tex_coord->data[2 + high];
|
|
||||||
out.position.x = (float(low) - 0.5f) * 2.0f;
|
|
||||||
out.position.y = (float(high) - 0.5f) * 2.0f;
|
|
||||||
out.position.z = 0.0f;
|
|
||||||
out.position.w = 1.0f;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment float4 fragmentMain(CopyVertexOut in [[stage_in]],
|
fragment float4 fragmentMain(CopyVertexOut in [[stage_in]],
|
||||||
constant Textures &textures [[buffer(22)]],
|
constant Textures &textures [[buffer(22)]],
|
||||||
uint sample_id [[sample_id]]) {
|
uint sample_id [[sample_id]]) {
|
||||||
|
|
27
src/Ryujinx.Graphics.Metal/Shaders/DepthBlit.metal
Normal file
27
src/Ryujinx.Graphics.Metal/Shaders/DepthBlit.metal
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include <metal_stdlib>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct CopyVertexOut {
|
||||||
|
float4 position [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Textures
|
||||||
|
{
|
||||||
|
texture2d<float, access::sample> texture;
|
||||||
|
sampler sampler;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentOut {
|
||||||
|
float depth [[depth(any)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment FragmentOut fragmentMain(CopyVertexOut in [[stage_in]],
|
||||||
|
constant Textures &textures [[buffer(22)]]) {
|
||||||
|
FragmentOut out;
|
||||||
|
|
||||||
|
out.depth = textures.texture.sample(textures.sampler, in.uv).r;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
29
src/Ryujinx.Graphics.Metal/Shaders/DepthBlitMs.metal
Normal file
29
src/Ryujinx.Graphics.Metal/Shaders/DepthBlitMs.metal
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include <metal_stdlib>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct CopyVertexOut {
|
||||||
|
float4 position [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Textures
|
||||||
|
{
|
||||||
|
texture2d_ms<float, access::read> texture;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentOut {
|
||||||
|
float depth [[depth(any)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment FragmentOut fragmentMain(CopyVertexOut in [[stage_in]],
|
||||||
|
constant Textures &textures [[buffer(22)]],
|
||||||
|
uint sample_id [[sample_id]]) {
|
||||||
|
FragmentOut out;
|
||||||
|
|
||||||
|
uint2 tex_size = uint2(textures.texture.get_width(), textures.texture.get_height());
|
||||||
|
uint2 tex_coord = uint2(in.uv * float2(tex_size));
|
||||||
|
out.depth = textures.texture.read(tex_coord, sample_id).r;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
27
src/Ryujinx.Graphics.Metal/Shaders/StencilBlit.metal
Normal file
27
src/Ryujinx.Graphics.Metal/Shaders/StencilBlit.metal
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include <metal_stdlib>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct CopyVertexOut {
|
||||||
|
float4 position [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Textures
|
||||||
|
{
|
||||||
|
texture2d<uint, access::sample> texture;
|
||||||
|
sampler sampler;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentOut {
|
||||||
|
uint stencil [[stencil]];
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment FragmentOut fragmentMain(CopyVertexOut in [[stage_in]],
|
||||||
|
constant Textures &textures [[buffer(22)]]) {
|
||||||
|
FragmentOut out;
|
||||||
|
|
||||||
|
out.stencil = textures.texture.sample(textures.sampler, in.uv).r;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
29
src/Ryujinx.Graphics.Metal/Shaders/StencilBlitMs.metal
Normal file
29
src/Ryujinx.Graphics.Metal/Shaders/StencilBlitMs.metal
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include <metal_stdlib>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct CopyVertexOut {
|
||||||
|
float4 position [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Textures
|
||||||
|
{
|
||||||
|
texture2d_ms<uint, access::read> texture;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentOut {
|
||||||
|
uint stencil [[stencil]];
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment FragmentOut fragmentMain(CopyVertexOut in [[stage_in]],
|
||||||
|
constant Textures &textures [[buffer(22)]],
|
||||||
|
uint sample_id [[sample_id]]) {
|
||||||
|
FragmentOut out;
|
||||||
|
|
||||||
|
uint2 tex_size = uint2(textures.texture.get_width(), textures.texture.get_height());
|
||||||
|
uint2 tex_coord = uint2(in.uv * float2(tex_size));
|
||||||
|
out.stencil = textures.texture.read(tex_coord, sample_id).r;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
|
@ -250,7 +250,9 @@ namespace Ryujinx.Graphics.Metal
|
||||||
|
|
||||||
var dst = (Texture)destination;
|
var dst = (Texture)destination;
|
||||||
|
|
||||||
Pipeline.Blit(this, dst, srcRegion, dstRegion, linearFilter);
|
bool isDepthOrStencil = dst.Info.Format.IsDepthOrStencil();
|
||||||
|
|
||||||
|
Pipeline.Blit(this, dst, srcRegion, dstRegion, isDepthOrStencil, linearFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyTo(BufferRange range, int layer, int level, int stride)
|
public void CopyTo(BufferRange range, int layer, int level, int stride)
|
||||||
|
|
Loading…
Reference in a new issue