Metal: Advanced Present (#6)
* Initial DrawTexture support & Advanced Present * TODO: Get Scissors Working * Chnage scissor state management * Rebase problems… * Rebase fixes again * Update DrawTexture + Fix Topology * Fix flipping * Add clear action support * Cleanup
This commit is contained in:
parent
1f91c74a95
commit
1f29a76ea3
8 changed files with 358 additions and 63 deletions
10
src/Ryujinx.Graphics.Metal/Effects/IPostProcessingEffect.cs
Normal file
10
src/Ryujinx.Graphics.Metal/Effects/IPostProcessingEffect.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Metal.Effects
|
||||
{
|
||||
internal interface IPostProcessingEffect : IDisposable
|
||||
{
|
||||
const int LocalGroupSize = 64;
|
||||
Texture Run(Texture view, int width, int height);
|
||||
}
|
||||
}
|
18
src/Ryujinx.Graphics.Metal/Effects/IScalingFilter.cs
Normal file
18
src/Ryujinx.Graphics.Metal/Effects/IScalingFilter.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Metal.Effects
|
||||
{
|
||||
internal interface IScalingFilter : IDisposable
|
||||
{
|
||||
float Level { get; set; }
|
||||
void Run(
|
||||
Texture view,
|
||||
Texture destinationTexture,
|
||||
Format format,
|
||||
int width,
|
||||
int height,
|
||||
Extents2D source,
|
||||
Extents2D destination);
|
||||
}
|
||||
}
|
|
@ -73,6 +73,9 @@ namespace Ryujinx.Graphics.Metal
|
|||
// Dirty flags
|
||||
public DirtyFlags Dirty = new();
|
||||
|
||||
// Only to be used for present
|
||||
public bool ClearLoadAction = false;
|
||||
|
||||
public EncoderState() { }
|
||||
|
||||
public EncoderState Clone()
|
||||
|
|
|
@ -24,8 +24,6 @@ namespace Ryujinx.Graphics.Metal
|
|||
public readonly MTLIndexType IndexType => _currentState.IndexType;
|
||||
public readonly ulong IndexBufferOffset => _currentState.IndexBufferOffset;
|
||||
public readonly PrimitiveTopology Topology => _currentState.Topology;
|
||||
public readonly Texture[] RenderTargets => _currentState.RenderTargets;
|
||||
public readonly Texture DepthStencil => _currentState.DepthStencil;
|
||||
|
||||
public EncoderStateManager(MTLDevice device, Pipeline pipeline)
|
||||
{
|
||||
|
@ -82,6 +80,11 @@ namespace Ryujinx.Graphics.Metal
|
|||
}
|
||||
}
|
||||
|
||||
public void SetClearLoadAction(bool clear)
|
||||
{
|
||||
_currentState.ClearLoadAction = clear;
|
||||
}
|
||||
|
||||
public MTLRenderCommandEncoder CreateRenderCommandEncoder()
|
||||
{
|
||||
// Initialise Pass & State
|
||||
|
@ -93,7 +96,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
{
|
||||
var passAttachment = renderPassDescriptor.ColorAttachments.Object((ulong)i);
|
||||
passAttachment.Texture = _currentState.RenderTargets[i].MTLTexture;
|
||||
passAttachment.LoadAction = MTLLoadAction.Load;
|
||||
passAttachment.LoadAction = _currentState.ClearLoadAction ? MTLLoadAction.Clear : MTLLoadAction.Load;
|
||||
passAttachment.StoreAction = MTLStoreAction.Store;
|
||||
}
|
||||
}
|
||||
|
@ -660,6 +663,8 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
// TODO: Handle 'zero' buffers
|
||||
for (int i = 0; i < attribDescriptors.Length; i++)
|
||||
{
|
||||
if (!attribDescriptors[i].IsZero)
|
||||
{
|
||||
var attrib = vertexDescriptor.Attributes.Object((ulong)i);
|
||||
attrib.Format = attribDescriptors[i].Format.Convert();
|
||||
|
@ -667,6 +672,11 @@ namespace Ryujinx.Graphics.Metal
|
|||
attrib.BufferIndex = (ulong)attribDescriptors[i].BufferIndex;
|
||||
attrib.Offset = (ulong)attribDescriptors[i].Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Logger.Warning?.PrintMsg(LogClass.Gpu, "Unhandled IsZero buffer!");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < bufferDescriptors.Length; i++)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,8 @@ namespace Ryujinx.Graphics.Metal
|
|||
private readonly Pipeline _pipeline;
|
||||
private MTLDevice _device;
|
||||
|
||||
private readonly ISampler _samplerLinear;
|
||||
private readonly ISampler _samplerNearest;
|
||||
private readonly IProgram _programColorBlit;
|
||||
private readonly List<IProgram> _programsColorClear = new();
|
||||
private readonly IProgram _programDepthStencilClear;
|
||||
|
@ -25,6 +27,9 @@ namespace Ryujinx.Graphics.Metal
|
|||
_device = device;
|
||||
_pipeline = pipeline;
|
||||
|
||||
_samplerNearest = new Sampler(_device, SamplerCreateInfo.Create(MinFilter.Nearest, MagFilter.Nearest));
|
||||
_samplerLinear = new Sampler(_device, SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear));
|
||||
|
||||
var blitSource = ReadMsl("Blit.metal");
|
||||
_programColorBlit = new Program(
|
||||
[
|
||||
|
@ -56,28 +61,140 @@ namespace Ryujinx.Graphics.Metal
|
|||
return EmbeddedResources.ReadAllText(string.Join('/', ShadersSourcePath, fileName));
|
||||
}
|
||||
|
||||
public void BlitColor(
|
||||
ITexture source,
|
||||
ITexture destination)
|
||||
public unsafe void BlitColor(
|
||||
ITexture src,
|
||||
ITexture dst,
|
||||
Extents2D srcRegion,
|
||||
Extents2D dstRegion,
|
||||
bool linearFilter)
|
||||
{
|
||||
var sampler = _device.NewSamplerState(new MTLSamplerDescriptor
|
||||
const int RegionBufferSize = 16;
|
||||
|
||||
var sampler = linearFilter ? _samplerLinear : _samplerNearest;
|
||||
|
||||
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)
|
||||
{
|
||||
MinFilter = MTLSamplerMinMagFilter.Nearest,
|
||||
MagFilter = MTLSamplerMinMagFilter.Nearest,
|
||||
MipFilter = MTLSamplerMipFilter.NotMipmapped
|
||||
});
|
||||
(region[0], region[1]) = (region[1], region[0]);
|
||||
}
|
||||
|
||||
if (dstRegion.Y1 > dstRegion.Y2)
|
||||
{
|
||||
(region[2], region[3]) = (region[3], region[2]);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||
|
||||
viewports[0] = new Viewport(
|
||||
rect,
|
||||
ViewportSwizzle.PositiveX,
|
||||
ViewportSwizzle.PositiveY,
|
||||
ViewportSwizzle.PositiveZ,
|
||||
ViewportSwizzle.PositiveW,
|
||||
0f,
|
||||
1f);
|
||||
|
||||
int dstWidth = dst.Width;
|
||||
int dstHeight = dst.Height;
|
||||
|
||||
// Save current state
|
||||
_pipeline.SaveAndResetState();
|
||||
|
||||
_pipeline.SetProgram(_programColorBlit);
|
||||
// Viewport and scissor needs to be set before render pass begin so as not to bind the old ones
|
||||
_pipeline.SetViewports([]);
|
||||
_pipeline.SetScissors([]);
|
||||
_pipeline.SetRenderTargets([destination], null);
|
||||
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, source, new Sampler(sampler));
|
||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.Triangles);
|
||||
_pipeline.Draw(6, 1, 0, 0);
|
||||
_pipeline.SetViewports(viewports);
|
||||
_pipeline.SetScissors(stackalloc Rectangle<int>[] { new Rectangle<int>(0, 0, dstWidth, dstHeight) });
|
||||
_pipeline.SetRenderTargets([dst], null);
|
||||
_pipeline.SetClearLoadAction(true);
|
||||
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, sampler);
|
||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||
|
||||
fixed (float* ptr = region)
|
||||
{
|
||||
_pipeline.GetOrCreateRenderEncoder().SetVertexBytes((IntPtr)ptr, RegionBufferSize, 0);
|
||||
}
|
||||
|
||||
_pipeline.Draw(4, 1, 0, 0);
|
||||
|
||||
// Restore previous state
|
||||
_pipeline.RestoreState();
|
||||
}
|
||||
|
||||
public unsafe void DrawTexture(
|
||||
ITexture src,
|
||||
ISampler srcSampler,
|
||||
Extents2DF srcRegion,
|
||||
Extents2DF dstRegion)
|
||||
{
|
||||
const int RegionBufferSize = 16;
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
|
||||
|
||||
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);
|
||||
|
||||
scissors[0] = new Rectangle<int>(0, 0, 0xFFFF, 0xFFFF);
|
||||
|
||||
// Save current state
|
||||
_pipeline.SaveState();
|
||||
|
||||
_pipeline.SetProgram(_programColorBlit);
|
||||
_pipeline.SetViewports(viewports);
|
||||
_pipeline.SetScissors(scissors);
|
||||
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, srcSampler);
|
||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||
_pipeline.SetFaceCulling(false, Face.FrontAndBack);
|
||||
// For some reason this results in a SIGSEGV
|
||||
// _pipeline.SetStencilTest(CreateStencilTestDescriptor(false));
|
||||
_pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
|
||||
|
||||
fixed (float* ptr = region)
|
||||
{
|
||||
_pipeline.GetOrCreateRenderEncoder().SetVertexBytes((IntPtr)ptr, RegionBufferSize, 0);
|
||||
}
|
||||
|
||||
_pipeline.Draw(4, 1, 0, 0);
|
||||
|
||||
// Restore previous state
|
||||
_pipeline.RestoreState();
|
||||
|
@ -169,6 +286,8 @@ namespace Ryujinx.Graphics.Metal
|
|||
}
|
||||
_programDepthStencilClear.Dispose();
|
||||
_pipeline.Dispose();
|
||||
_samplerLinear.Dispose();
|
||||
_samplerNearest.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,11 @@ namespace Ryujinx.Graphics.Metal
|
|||
_encoderStateManager.RestoreState();
|
||||
}
|
||||
|
||||
public void SetClearLoadAction(bool clear)
|
||||
{
|
||||
_encoderStateManager.SetClearLoadAction(clear);
|
||||
}
|
||||
|
||||
public MTLRenderCommandEncoder GetOrCreateRenderEncoder()
|
||||
{
|
||||
MTLRenderCommandEncoder renderCommandEncoder;
|
||||
|
@ -167,22 +172,17 @@ namespace Ryujinx.Graphics.Metal
|
|||
return computeCommandEncoder;
|
||||
}
|
||||
|
||||
public void Present(CAMetalDrawable drawable, ITexture texture)
|
||||
public void Present(CAMetalDrawable drawable, Texture src, Extents2D srcRegion, Extents2D dstRegion, bool isLinear)
|
||||
{
|
||||
if (texture is not Texture tex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EndCurrentPass();
|
||||
|
||||
SaveState();
|
||||
|
||||
// TODO: Clean this up
|
||||
var textureInfo = new TextureCreateInfo((int)drawable.Texture.Width, (int)drawable.Texture.Height, (int)drawable.Texture.Depth, (int)drawable.Texture.MipmapLevelCount, (int)drawable.Texture.SampleCount, 0, 0, 0, Format.B8G8R8A8Unorm, 0, Target.Texture2D, SwizzleComponent.Red, SwizzleComponent.Green, SwizzleComponent.Blue, SwizzleComponent.Alpha);
|
||||
var dest = new Texture(_device, this, textureInfo, drawable.Texture, 0, 0);
|
||||
var dst = new Texture(_device, this, textureInfo, drawable.Texture, 0, 0);
|
||||
|
||||
_helperShader.BlitColor(tex, dest);
|
||||
_helperShader.BlitColor(src, dst, srcRegion, dstRegion, isLinear);
|
||||
|
||||
EndCurrentPass();
|
||||
|
||||
|
@ -194,7 +194,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
RestoreState();
|
||||
|
||||
// Cleanup
|
||||
dest.Dispose();
|
||||
dst.Dispose();
|
||||
}
|
||||
|
||||
public void Barrier()
|
||||
|
@ -338,9 +338,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion)
|
||||
{
|
||||
// var renderCommandEncoder = GetOrCreateRenderEncoder();
|
||||
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
|
||||
_helperShader.DrawTexture(texture, sampler, srcRegion, dstRegion);
|
||||
}
|
||||
|
||||
public void SetAlphaTest(bool enable, float reference, CompareOp op)
|
||||
|
|
|
@ -2,32 +2,23 @@
|
|||
|
||||
using namespace metal;
|
||||
|
||||
// ------------------
|
||||
// Simple Blit Shader
|
||||
// ------------------
|
||||
|
||||
constant float2 quadVertices[] = {
|
||||
float2(-1, -1),
|
||||
float2(-1, 1),
|
||||
float2( 1, 1),
|
||||
float2(-1, -1),
|
||||
float2( 1, 1),
|
||||
float2( 1, -1)
|
||||
};
|
||||
|
||||
struct CopyVertexOut {
|
||||
float4 position [[position]];
|
||||
float2 uv;
|
||||
};
|
||||
|
||||
vertex CopyVertexOut vertexMain(unsigned short vid [[vertex_id]]) {
|
||||
float2 position = quadVertices[vid];
|
||||
|
||||
vertex CopyVertexOut vertexMain(uint vid [[vertex_id]],
|
||||
const device float* texCoord [[buffer(0)]]) {
|
||||
CopyVertexOut out;
|
||||
|
||||
out.position = float4(position, 0, 1);
|
||||
out.position.y = -out.position.y;
|
||||
out.uv = position * 0.5f + 0.5f;
|
||||
int low = vid & 1;
|
||||
int high = vid >> 1;
|
||||
out.uv.x = texCoord[low];
|
||||
out.uv.y = texCoord[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;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Metal.Effects;
|
||||
using SharpMetal.ObjectiveCCore;
|
||||
using SharpMetal.QuartzCore;
|
||||
using System;
|
||||
|
@ -10,51 +11,196 @@ namespace Ryujinx.Graphics.Metal
|
|||
[SupportedOSPlatform("macos")]
|
||||
class Window : IWindow, IDisposable
|
||||
{
|
||||
public bool ScreenCaptureRequested { get; set; }
|
||||
|
||||
private readonly MetalRenderer _renderer;
|
||||
private readonly CAMetalLayer _metalLayer;
|
||||
|
||||
private int _width;
|
||||
private int _height;
|
||||
private bool _vsyncEnabled;
|
||||
private AntiAliasing _currentAntiAliasing;
|
||||
private bool _updateEffect;
|
||||
private IPostProcessingEffect _effect;
|
||||
private IScalingFilter _scalingFilter;
|
||||
private bool _isLinear;
|
||||
private float _scalingFilterLevel;
|
||||
private bool _updateScalingFilter;
|
||||
private ScalingFilter _currentScalingFilter;
|
||||
private bool _colorSpacePassthroughEnabled;
|
||||
|
||||
public Window(MetalRenderer renderer, CAMetalLayer metalLayer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
_metalLayer = metalLayer;
|
||||
}
|
||||
|
||||
// TODO: Handle ImageCrop
|
||||
public void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
|
||||
{
|
||||
if (_renderer.Pipeline is Pipeline pipeline && texture is Texture tex)
|
||||
{
|
||||
var drawable = new CAMetalDrawable(ObjectiveC.IntPtr_objc_msgSend(_metalLayer, "nextDrawable"));
|
||||
pipeline.Present(drawable, tex);
|
||||
|
||||
_width = (int)drawable.Texture.Width;
|
||||
_height = (int)drawable.Texture.Height;
|
||||
|
||||
UpdateEffect();
|
||||
|
||||
if (_effect != null)
|
||||
{
|
||||
// TODO: Run Effects
|
||||
// view = _effect.Run()
|
||||
}
|
||||
|
||||
int srcX0, srcX1, srcY0, srcY1;
|
||||
|
||||
if (crop.Left == 0 && crop.Right == 0)
|
||||
{
|
||||
srcX0 = 0;
|
||||
srcX1 = tex.Width;
|
||||
}
|
||||
else
|
||||
{
|
||||
srcX0 = crop.Left;
|
||||
srcX1 = crop.Right;
|
||||
}
|
||||
|
||||
if (crop.Top == 0 && crop.Bottom == 0)
|
||||
{
|
||||
srcY0 = 0;
|
||||
srcY1 = tex.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
srcY0 = crop.Top;
|
||||
srcY1 = crop.Bottom;
|
||||
}
|
||||
|
||||
if (ScreenCaptureRequested)
|
||||
{
|
||||
// TODO: Support screen captures
|
||||
|
||||
ScreenCaptureRequested = false;
|
||||
}
|
||||
|
||||
float ratioX = crop.IsStretched ? 1.0f : MathF.Min(1.0f, _height * crop.AspectRatioX / (_width * crop.AspectRatioY));
|
||||
float ratioY = crop.IsStretched ? 1.0f : MathF.Min(1.0f, _width * crop.AspectRatioY / (_height * crop.AspectRatioX));
|
||||
|
||||
int dstWidth = (int)(_width * ratioX);
|
||||
int dstHeight = (int)(_height * ratioY);
|
||||
|
||||
int dstPaddingX = (_width - dstWidth) / 2;
|
||||
int dstPaddingY = (_height - dstHeight) / 2;
|
||||
|
||||
int dstX0 = crop.FlipX ? _width - dstPaddingX : dstPaddingX;
|
||||
int dstX1 = crop.FlipX ? dstPaddingX : _width - dstPaddingX;
|
||||
|
||||
int dstY0 = crop.FlipY ? _height - dstPaddingY : dstPaddingY;
|
||||
int dstY1 = crop.FlipY ? dstPaddingY : _height - dstPaddingY;
|
||||
|
||||
if (_scalingFilter != null)
|
||||
{
|
||||
// TODO: Run scaling filter
|
||||
}
|
||||
|
||||
pipeline.Present(
|
||||
drawable,
|
||||
tex,
|
||||
new Extents2D(srcX0, srcY0, srcX1, srcY1),
|
||||
new Extents2D(dstX0, dstY0, dstX1, dstY1),
|
||||
_isLinear);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSize(int width, int height)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
|
||||
// Ignore
|
||||
}
|
||||
|
||||
public void ChangeVSyncMode(bool vsyncEnabled)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
|
||||
_vsyncEnabled = vsyncEnabled;
|
||||
}
|
||||
|
||||
public void SetAntiAliasing(AntiAliasing antialiasing)
|
||||
public void SetAntiAliasing(AntiAliasing effect)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
|
||||
if (_currentAntiAliasing == effect && _effect != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_currentAntiAliasing = effect;
|
||||
|
||||
_updateEffect = true;
|
||||
}
|
||||
|
||||
public void SetScalingFilter(ScalingFilter type)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
|
||||
if (_currentScalingFilter == type && _effect != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_currentScalingFilter = type;
|
||||
|
||||
_updateScalingFilter = true;
|
||||
}
|
||||
|
||||
public void SetScalingFilterLevel(float level)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
|
||||
_scalingFilterLevel = level;
|
||||
_updateScalingFilter = true;
|
||||
}
|
||||
|
||||
public void SetColorSpacePassthrough(bool colorSpacePassThroughEnabled) { }
|
||||
public void SetColorSpacePassthrough(bool colorSpacePassThroughEnabled)
|
||||
{
|
||||
_colorSpacePassthroughEnabled = colorSpacePassThroughEnabled;
|
||||
}
|
||||
|
||||
private void UpdateEffect()
|
||||
{
|
||||
if (_updateEffect)
|
||||
{
|
||||
_updateEffect = false;
|
||||
|
||||
switch (_currentAntiAliasing)
|
||||
{
|
||||
case AntiAliasing.Fxaa:
|
||||
_effect?.Dispose();
|
||||
Logger.Warning?.PrintMsg(LogClass.Gpu, "FXAA not implemented for Metal backend!");
|
||||
break;
|
||||
case AntiAliasing.None:
|
||||
_effect?.Dispose();
|
||||
_effect = null;
|
||||
break;
|
||||
case AntiAliasing.SmaaLow:
|
||||
case AntiAliasing.SmaaMedium:
|
||||
case AntiAliasing.SmaaHigh:
|
||||
case AntiAliasing.SmaaUltra:
|
||||
var quality = _currentAntiAliasing - AntiAliasing.SmaaLow;
|
||||
Logger.Warning?.PrintMsg(LogClass.Gpu, "SMAA not implemented for Metal backend!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_updateScalingFilter)
|
||||
{
|
||||
_updateScalingFilter = false;
|
||||
|
||||
switch (_currentScalingFilter)
|
||||
{
|
||||
case ScalingFilter.Bilinear:
|
||||
case ScalingFilter.Nearest:
|
||||
_scalingFilter?.Dispose();
|
||||
_scalingFilter = null;
|
||||
_isLinear = _currentScalingFilter == ScalingFilter.Bilinear;
|
||||
break;
|
||||
case ScalingFilter.Fsr:
|
||||
Logger.Warning?.PrintMsg(LogClass.Gpu, "FSR not implemented for Metal backend!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue