2024-05-18 22:54:55 +00:00
|
|
|
using Ryujinx.Common;
|
|
|
|
using Ryujinx.Graphics.GAL;
|
|
|
|
using Ryujinx.Graphics.Shader;
|
|
|
|
using Ryujinx.Graphics.Shader.Translation;
|
|
|
|
using SharpMetal.Metal;
|
|
|
|
using System;
|
2024-05-24 13:28:16 +00:00
|
|
|
using System.Collections.Generic;
|
2024-05-18 22:54:55 +00:00
|
|
|
using System.Runtime.Versioning;
|
|
|
|
|
|
|
|
namespace Ryujinx.Graphics.Metal
|
|
|
|
{
|
|
|
|
[SupportedOSPlatform("macos")]
|
2024-06-20 23:21:06 +00:00
|
|
|
class HelperShader : IDisposable
|
2024-05-18 22:54:55 +00:00
|
|
|
{
|
2024-06-20 11:59:29 +00:00
|
|
|
private const int ConvertElementsPerWorkgroup = 32 * 100; // Work group size of 32 times 100 elements.
|
2024-05-18 22:54:55 +00:00
|
|
|
private const string ShadersSourcePath = "/Ryujinx.Graphics.Metal/Shaders";
|
2024-06-20 11:59:29 +00:00
|
|
|
private readonly MetalRenderer _renderer;
|
2024-05-19 00:40:37 +00:00
|
|
|
private readonly Pipeline _pipeline;
|
2024-05-18 22:54:55 +00:00
|
|
|
private MTLDevice _device;
|
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
private readonly ISampler _samplerLinear;
|
|
|
|
private readonly ISampler _samplerNearest;
|
2024-05-18 22:54:55 +00:00
|
|
|
private readonly IProgram _programColorBlit;
|
2024-05-24 13:28:16 +00:00
|
|
|
private readonly List<IProgram> _programsColorClear = new();
|
2024-05-18 22:54:55 +00:00
|
|
|
private readonly IProgram _programDepthStencilClear;
|
2024-06-20 11:59:29 +00:00
|
|
|
private readonly IProgram _programStrideChange;
|
2024-05-18 22:54:55 +00:00
|
|
|
|
2024-06-28 20:14:53 +00:00
|
|
|
private readonly EncoderState _helperShaderState = new();
|
|
|
|
|
2024-06-20 11:59:29 +00:00
|
|
|
public HelperShader(MTLDevice device, MetalRenderer renderer, Pipeline pipeline)
|
2024-05-18 22:54:55 +00:00
|
|
|
{
|
|
|
|
_device = device;
|
2024-06-20 11:59:29 +00:00
|
|
|
_renderer = renderer;
|
2024-05-18 22:54:55 +00:00
|
|
|
_pipeline = pipeline;
|
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
_samplerNearest = new Sampler(_device, SamplerCreateInfo.Create(MinFilter.Nearest, MagFilter.Nearest));
|
|
|
|
_samplerLinear = new Sampler(_device, SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear));
|
|
|
|
|
2024-07-01 17:24:10 +00:00
|
|
|
var blitResourceLayout = new ResourceLayoutBuilder()
|
|
|
|
.Add(ResourceStages.Vertex, ResourceType.UniformBuffer, 0)
|
|
|
|
.Add(ResourceStages.Fragment, ResourceType.TextureAndSampler, 0).Build();
|
|
|
|
|
2024-05-18 22:54:55 +00:00
|
|
|
var blitSource = ReadMsl("Blit.metal");
|
|
|
|
_programColorBlit = new Program(
|
|
|
|
[
|
|
|
|
new ShaderSource(blitSource, ShaderStage.Fragment, TargetLanguage.Msl),
|
|
|
|
new ShaderSource(blitSource, ShaderStage.Vertex, TargetLanguage.Msl)
|
2024-07-01 17:24:10 +00:00
|
|
|
], blitResourceLayout, device);
|
|
|
|
|
|
|
|
var colorClearResourceLayout = new ResourceLayoutBuilder()
|
|
|
|
.Add(ResourceStages.Fragment, ResourceType.UniformBuffer, 0).Build();
|
2024-05-18 22:54:55 +00:00
|
|
|
|
2024-05-22 21:21:44 +00:00
|
|
|
var colorClearSource = ReadMsl("ColorClear.metal");
|
2024-05-24 13:28:16 +00:00
|
|
|
for (int i = 0; i < Constants.MaxColorAttachments; i++)
|
|
|
|
{
|
|
|
|
var crntSource = colorClearSource.Replace("COLOR_ATTACHMENT_INDEX", i.ToString());
|
|
|
|
_programsColorClear.Add(new Program(
|
|
|
|
[
|
|
|
|
new ShaderSource(crntSource, ShaderStage.Fragment, TargetLanguage.Msl),
|
|
|
|
new ShaderSource(crntSource, ShaderStage.Vertex, TargetLanguage.Msl)
|
2024-07-01 17:24:10 +00:00
|
|
|
], colorClearResourceLayout, device));
|
2024-05-24 13:28:16 +00:00
|
|
|
}
|
2024-05-22 21:21:44 +00:00
|
|
|
|
2024-05-23 00:26:54 +00:00
|
|
|
var depthStencilClearSource = ReadMsl("DepthStencilClear.metal");
|
|
|
|
_programDepthStencilClear = new Program(
|
|
|
|
[
|
|
|
|
new ShaderSource(depthStencilClearSource, ShaderStage.Fragment, TargetLanguage.Msl),
|
|
|
|
new ShaderSource(depthStencilClearSource, ShaderStage.Vertex, TargetLanguage.Msl)
|
2024-07-01 17:24:10 +00:00
|
|
|
], colorClearResourceLayout, device);
|
|
|
|
|
|
|
|
var strideChangeResourceLayout = new ResourceLayoutBuilder()
|
|
|
|
.Add(ResourceStages.Compute, ResourceType.UniformBuffer, 0)
|
|
|
|
.Add(ResourceStages.Compute, ResourceType.StorageBuffer, 1)
|
|
|
|
.Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2).Build();
|
2024-06-20 11:59:29 +00:00
|
|
|
|
|
|
|
var strideChangeSource = ReadMsl("ChangeBufferStride.metal");
|
|
|
|
_programStrideChange = new Program(
|
|
|
|
[
|
|
|
|
new ShaderSource(strideChangeSource, ShaderStage.Compute, TargetLanguage.Msl)
|
2024-07-01 17:24:10 +00:00
|
|
|
], strideChangeResourceLayout, device, new ComputeSize(64, 1, 1));
|
2024-05-18 22:54:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private static string ReadMsl(string fileName)
|
|
|
|
{
|
|
|
|
return EmbeddedResources.ReadAllText(string.Join('/', ShadersSourcePath, fileName));
|
|
|
|
}
|
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
public unsafe void BlitColor(
|
2024-06-20 11:59:29 +00:00
|
|
|
CommandBufferScoped cbs,
|
2024-05-27 13:47:50 +00:00
|
|
|
ITexture src,
|
|
|
|
ITexture dst,
|
|
|
|
Extents2D srcRegion,
|
|
|
|
Extents2D dstRegion,
|
2024-06-25 13:25:31 +00:00
|
|
|
bool linearFilter,
|
|
|
|
bool clear = false)
|
2024-05-18 22:54:55 +00:00
|
|
|
{
|
2024-06-28 20:14:53 +00:00
|
|
|
_pipeline.SwapState(_helperShaderState);
|
2024-06-20 13:14:05 +00:00
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
const int RegionBufferSize = 16;
|
|
|
|
|
|
|
|
var sampler = linearFilter ? _samplerLinear : _samplerNearest;
|
|
|
|
|
2024-06-20 13:14:05 +00:00
|
|
|
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, sampler);
|
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
|
|
|
|
|
2024-05-27 20:54:26 +00:00
|
|
|
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;
|
2024-05-27 13:47:50 +00:00
|
|
|
|
|
|
|
if (dstRegion.X1 > dstRegion.X2)
|
2024-05-18 22:54:55 +00:00
|
|
|
{
|
2024-05-27 13:47:50 +00:00
|
|
|
(region[0], region[1]) = (region[1], region[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dstRegion.Y1 > dstRegion.Y2)
|
|
|
|
{
|
|
|
|
(region[2], region[3]) = (region[3], region[2]);
|
|
|
|
}
|
|
|
|
|
2024-06-20 13:14:05 +00:00
|
|
|
using var buffer = _renderer.BufferManager.ReserveOrCreate(cbs, RegionBufferSize);
|
|
|
|
buffer.Holder.SetDataUnchecked<float>(buffer.Offset, region);
|
|
|
|
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
|
2024-06-20 11:59:29 +00:00
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
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));
|
|
|
|
|
2024-07-01 22:36:11 +00:00
|
|
|
Span<Viewport> viewports = stackalloc Viewport[16];
|
2024-05-27 13:47:50 +00:00
|
|
|
|
|
|
|
viewports[0] = new Viewport(
|
|
|
|
rect,
|
|
|
|
ViewportSwizzle.PositiveX,
|
|
|
|
ViewportSwizzle.PositiveY,
|
|
|
|
ViewportSwizzle.PositiveZ,
|
|
|
|
ViewportSwizzle.PositiveW,
|
|
|
|
0f,
|
|
|
|
1f);
|
|
|
|
|
2024-06-20 13:14:05 +00:00
|
|
|
_pipeline.SetProgram(_programColorBlit);
|
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
int dstWidth = dst.Width;
|
|
|
|
int dstHeight = dst.Height;
|
2024-05-18 22:54:55 +00:00
|
|
|
|
2024-07-01 22:36:11 +00:00
|
|
|
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[16];
|
|
|
|
|
|
|
|
scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight);
|
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
_pipeline.SetRenderTargets([dst], null);
|
2024-07-01 22:36:11 +00:00
|
|
|
_pipeline.SetScissors(scissors);
|
2024-05-27 13:47:50 +00:00
|
|
|
|
2024-06-25 13:25:31 +00:00
|
|
|
_pipeline.SetClearLoadAction(clear);
|
2024-05-27 13:47:50 +00:00
|
|
|
|
2024-06-20 13:14:05 +00:00
|
|
|
_pipeline.SetViewports(viewports);
|
|
|
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
2024-05-27 13:47:50 +00:00
|
|
|
_pipeline.Draw(4, 1, 0, 0);
|
|
|
|
|
2024-06-28 20:14:53 +00:00
|
|
|
// Cleanup
|
|
|
|
if (clear)
|
|
|
|
{
|
|
|
|
_pipeline.SetClearLoadAction(false);
|
|
|
|
}
|
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
// Restore previous state
|
2024-06-28 20:14:53 +00:00
|
|
|
_pipeline.SwapState(null);
|
2024-05-27 13:47:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public unsafe void DrawTexture(
|
|
|
|
ITexture src,
|
|
|
|
ISampler srcSampler,
|
|
|
|
Extents2DF srcRegion,
|
|
|
|
Extents2DF dstRegion)
|
|
|
|
{
|
2024-06-20 13:25:40 +00:00
|
|
|
// Save current state
|
2024-06-28 20:14:53 +00:00
|
|
|
var state = _pipeline.SavePredrawState();
|
|
|
|
|
|
|
|
_pipeline.SetFaceCulling(false, Face.Front);
|
|
|
|
_pipeline.SetStencilTest(new StencilTestDescriptor());
|
|
|
|
_pipeline.SetDepthTest(new DepthTestDescriptor());
|
2024-06-20 13:25:40 +00:00
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
const int RegionBufferSize = 16;
|
|
|
|
|
2024-06-20 13:25:40 +00:00
|
|
|
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, srcSampler);
|
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
|
|
|
|
|
|
|
|
region[0] = srcRegion.X1 / src.Width;
|
|
|
|
region[1] = srcRegion.X2 / src.Width;
|
|
|
|
region[2] = srcRegion.Y1 / src.Height;
|
|
|
|
region[3] = srcRegion.Y2 / 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]);
|
|
|
|
}
|
|
|
|
|
2024-06-20 13:25:40 +00:00
|
|
|
var bufferHandle = _renderer.BufferManager.CreateWithHandle(RegionBufferSize);
|
|
|
|
_renderer.BufferManager.SetData<float>(bufferHandle, 0, region);
|
|
|
|
_pipeline.SetUniformBuffers([new BufferAssignment(0, new BufferRange(bufferHandle, 0, RegionBufferSize))]);
|
2024-06-20 11:59:29 +00:00
|
|
|
|
2024-07-01 22:36:11 +00:00
|
|
|
Span<Viewport> viewports = stackalloc Viewport[16];
|
2024-05-27 13:47:50 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
_pipeline.SetProgram(_programColorBlit);
|
|
|
|
_pipeline.SetViewports(viewports);
|
|
|
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
|
|
|
_pipeline.Draw(4, 1, 0, 0);
|
2024-05-24 13:09:06 +00:00
|
|
|
|
2024-06-20 13:25:40 +00:00
|
|
|
_renderer.BufferManager.Delete(bufferHandle);
|
|
|
|
|
2024-05-24 13:09:06 +00:00
|
|
|
// Restore previous state
|
2024-06-28 20:14:53 +00:00
|
|
|
_pipeline.RestorePredrawState(state);
|
2024-05-18 22:54:55 +00:00
|
|
|
}
|
|
|
|
|
2024-06-20 11:59:29 +00:00
|
|
|
public void ConvertI8ToI16(CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size)
|
|
|
|
{
|
|
|
|
ChangeStride(cbs, src, dst, srcOffset, size, 1, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
public unsafe void ChangeStride(
|
|
|
|
CommandBufferScoped cbs,
|
|
|
|
BufferHolder src,
|
|
|
|
BufferHolder dst,
|
|
|
|
int srcOffset,
|
|
|
|
int size,
|
|
|
|
int stride,
|
|
|
|
int newStride)
|
|
|
|
{
|
|
|
|
int elems = size / stride;
|
|
|
|
|
|
|
|
var srcBuffer = src.GetBuffer();
|
|
|
|
var dstBuffer = dst.GetBuffer();
|
|
|
|
|
|
|
|
const int ParamsBufferSize = 16;
|
|
|
|
|
|
|
|
// Save current state
|
2024-06-28 20:14:53 +00:00
|
|
|
_pipeline.SwapState(_helperShaderState);
|
2024-06-20 11:59:29 +00:00
|
|
|
|
|
|
|
Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
|
|
|
|
|
|
|
|
shaderParams[0] = stride;
|
|
|
|
shaderParams[1] = newStride;
|
|
|
|
shaderParams[2] = size;
|
|
|
|
shaderParams[3] = srcOffset;
|
|
|
|
|
|
|
|
using var buffer = _renderer.BufferManager.ReserveOrCreate(cbs, ParamsBufferSize);
|
|
|
|
buffer.Holder.SetDataUnchecked<int>(buffer.Offset, shaderParams);
|
|
|
|
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
|
|
|
|
|
|
|
|
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
|
|
|
|
|
|
|
|
sbRanges[0] = srcBuffer;
|
|
|
|
sbRanges[1] = dstBuffer;
|
|
|
|
_pipeline.SetStorageBuffers(1, sbRanges);
|
|
|
|
|
|
|
|
_pipeline.SetProgram(_programStrideChange);
|
2024-06-29 18:07:07 +00:00
|
|
|
_pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1);
|
2024-06-20 11:59:29 +00:00
|
|
|
|
|
|
|
// Restore previous state
|
2024-06-28 20:14:53 +00:00
|
|
|
_pipeline.SwapState(null);
|
2024-06-20 11:59:29 +00:00
|
|
|
}
|
|
|
|
|
2024-05-22 21:21:44 +00:00
|
|
|
public unsafe void ClearColor(
|
2024-05-24 13:28:16 +00:00
|
|
|
int index,
|
2024-05-30 12:20:16 +00:00
|
|
|
ReadOnlySpan<float> clearColor,
|
|
|
|
uint componentMask,
|
|
|
|
int dstWidth,
|
|
|
|
int dstHeight)
|
2024-05-18 22:54:55 +00:00
|
|
|
{
|
2024-06-28 20:14:53 +00:00
|
|
|
// Keep original scissor
|
|
|
|
DirtyFlags clearFlags = DirtyFlags.All & (~DirtyFlags.Scissors);
|
|
|
|
|
2024-05-24 13:09:06 +00:00
|
|
|
// Save current state
|
2024-06-30 16:23:53 +00:00
|
|
|
EncoderState originalState = _pipeline.SwapState(_helperShaderState, clearFlags, false);
|
2024-06-28 20:14:53 +00:00
|
|
|
|
|
|
|
// Inherit some state without fully recreating render pipeline.
|
|
|
|
RenderTargetCopy save = _helperShaderState.InheritForClear(originalState, false, index);
|
2024-05-24 13:09:06 +00:00
|
|
|
|
2024-06-20 13:25:40 +00:00
|
|
|
const int ClearColorBufferSize = 16;
|
|
|
|
|
|
|
|
// TODO: Flush
|
|
|
|
|
2024-06-20 23:21:06 +00:00
|
|
|
using var buffer = _renderer.BufferManager.ReserveOrCreate(_pipeline.Cbs, ClearColorBufferSize);
|
2024-06-20 13:25:40 +00:00
|
|
|
buffer.Holder.SetDataUnchecked(buffer.Offset, clearColor);
|
|
|
|
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
|
|
|
|
|
2024-07-01 22:36:11 +00:00
|
|
|
Span<Viewport> viewports = stackalloc Viewport[16];
|
2024-05-30 12:20:16 +00:00
|
|
|
|
|
|
|
// TODO: Set exact viewport!
|
|
|
|
viewports[0] = new Viewport(
|
|
|
|
new Rectangle<float>(0, 0, dstWidth, dstHeight),
|
|
|
|
ViewportSwizzle.PositiveX,
|
|
|
|
ViewportSwizzle.PositiveY,
|
|
|
|
ViewportSwizzle.PositiveZ,
|
|
|
|
ViewportSwizzle.PositiveW,
|
|
|
|
0f,
|
|
|
|
1f);
|
|
|
|
|
2024-07-03 09:27:03 +00:00
|
|
|
Span<uint> componentMasks = stackalloc uint[index + 1];
|
|
|
|
componentMasks[index] = componentMask;
|
|
|
|
|
2024-05-24 13:28:16 +00:00
|
|
|
_pipeline.SetProgram(_programsColorClear[index]);
|
2024-06-28 20:14:53 +00:00
|
|
|
_pipeline.SetBlendState(index, new BlendDescriptor());
|
2024-06-20 13:29:45 +00:00
|
|
|
_pipeline.SetFaceCulling(false, Face.Front);
|
|
|
|
_pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
|
2024-07-03 09:27:03 +00:00
|
|
|
_pipeline.SetRenderTargetColorMasks(componentMasks);
|
2024-05-30 12:20:16 +00:00
|
|
|
_pipeline.SetViewports(viewports);
|
2024-06-20 13:25:40 +00:00
|
|
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
2024-05-18 22:54:55 +00:00
|
|
|
_pipeline.Draw(4, 1, 0, 0);
|
2024-05-24 13:09:06 +00:00
|
|
|
|
|
|
|
// Restore previous state
|
2024-06-30 16:23:53 +00:00
|
|
|
_pipeline.SwapState(null, clearFlags, false);
|
2024-06-28 20:14:53 +00:00
|
|
|
|
|
|
|
_helperShaderState.Restore(save);
|
2024-05-18 22:54:55 +00:00
|
|
|
}
|
|
|
|
|
2024-05-23 00:26:54 +00:00
|
|
|
public unsafe void ClearDepthStencil(
|
2024-05-27 11:58:03 +00:00
|
|
|
float depthValue,
|
2024-05-18 22:54:55 +00:00
|
|
|
bool depthMask,
|
|
|
|
int stencilValue,
|
2024-05-30 12:20:16 +00:00
|
|
|
int stencilMask,
|
|
|
|
int dstWidth,
|
|
|
|
int dstHeight)
|
2024-05-18 22:54:55 +00:00
|
|
|
{
|
2024-06-28 20:14:53 +00:00
|
|
|
// Keep original scissor
|
|
|
|
DirtyFlags clearFlags = DirtyFlags.All & (~DirtyFlags.Scissors);
|
|
|
|
var helperScissors = _helperShaderState.Scissors;
|
|
|
|
|
2024-05-24 13:09:06 +00:00
|
|
|
// Save current state
|
2024-06-30 16:23:53 +00:00
|
|
|
EncoderState originalState = _pipeline.SwapState(_helperShaderState, clearFlags, false);
|
2024-06-28 20:14:53 +00:00
|
|
|
|
|
|
|
// Inherit some state without fully recreating render pipeline.
|
|
|
|
RenderTargetCopy save = _helperShaderState.InheritForClear(originalState, true);
|
2024-05-24 13:09:06 +00:00
|
|
|
|
2024-06-26 16:38:23 +00:00
|
|
|
const int ClearDepthBufferSize = 16;
|
2024-06-25 13:25:31 +00:00
|
|
|
|
|
|
|
using var buffer = _renderer.BufferManager.ReserveOrCreate(_pipeline.Cbs, ClearDepthBufferSize);
|
|
|
|
buffer.Holder.SetDataUnchecked(buffer.Offset, new ReadOnlySpan<float>(ref depthValue));
|
|
|
|
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
|
|
|
|
|
2024-05-30 12:20:16 +00:00
|
|
|
Span<Viewport> viewports = stackalloc Viewport[1];
|
|
|
|
|
|
|
|
viewports[0] = new Viewport(
|
|
|
|
new Rectangle<float>(0, 0, dstWidth, dstHeight),
|
|
|
|
ViewportSwizzle.PositiveX,
|
|
|
|
ViewportSwizzle.PositiveY,
|
|
|
|
ViewportSwizzle.PositiveZ,
|
|
|
|
ViewportSwizzle.PositiveW,
|
|
|
|
0f,
|
|
|
|
1f);
|
|
|
|
|
2024-05-18 22:54:55 +00:00
|
|
|
_pipeline.SetProgram(_programDepthStencilClear);
|
2024-05-25 07:51:56 +00:00
|
|
|
_pipeline.SetFaceCulling(false, Face.Front);
|
2024-05-18 22:54:55 +00:00
|
|
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
2024-05-30 12:20:16 +00:00
|
|
|
_pipeline.SetViewports(viewports);
|
2024-05-18 22:54:55 +00:00
|
|
|
_pipeline.SetDepthTest(new DepthTestDescriptor(true, depthMask, CompareOp.Always));
|
2024-06-20 20:08:28 +00:00
|
|
|
_pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xFF, stencilMask));
|
2024-05-18 22:54:55 +00:00
|
|
|
_pipeline.Draw(4, 1, 0, 0);
|
2024-05-24 13:09:06 +00:00
|
|
|
|
2024-06-28 20:14:53 +00:00
|
|
|
// Cleanup
|
|
|
|
_pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
|
|
|
|
_pipeline.SetStencilTest(CreateStencilTestDescriptor(false));
|
|
|
|
|
2024-05-24 13:09:06 +00:00
|
|
|
// Restore previous state
|
2024-06-30 16:23:53 +00:00
|
|
|
_pipeline.SwapState(null, clearFlags, false);
|
2024-06-28 20:14:53 +00:00
|
|
|
|
|
|
|
_helperShaderState.Restore(save);
|
2024-05-18 22:54:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private static StencilTestDescriptor CreateStencilTestDescriptor(
|
|
|
|
bool enabled,
|
|
|
|
int refValue = 0,
|
|
|
|
int compareMask = 0xff,
|
|
|
|
int writeMask = 0xff)
|
|
|
|
{
|
|
|
|
return new StencilTestDescriptor(
|
|
|
|
enabled,
|
|
|
|
CompareOp.Always,
|
|
|
|
StencilOp.Replace,
|
|
|
|
StencilOp.Replace,
|
|
|
|
StencilOp.Replace,
|
|
|
|
refValue,
|
|
|
|
compareMask,
|
|
|
|
writeMask,
|
|
|
|
CompareOp.Always,
|
|
|
|
StencilOp.Replace,
|
|
|
|
StencilOp.Replace,
|
|
|
|
StencilOp.Replace,
|
|
|
|
refValue,
|
|
|
|
compareMask,
|
|
|
|
writeMask);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
{
|
|
|
|
_programColorBlit.Dispose();
|
2024-05-24 13:28:16 +00:00
|
|
|
foreach (var programColorClear in _programsColorClear)
|
|
|
|
{
|
|
|
|
programColorClear.Dispose();
|
|
|
|
}
|
2024-05-18 22:54:55 +00:00
|
|
|
_programDepthStencilClear.Dispose();
|
|
|
|
_pipeline.Dispose();
|
2024-05-27 13:47:50 +00:00
|
|
|
_samplerLinear.Dispose();
|
|
|
|
_samplerNearest.Dispose();
|
2024-05-18 22:54:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|