Ryujinx/src/Ryujinx.Graphics.Metal/Window.cs

211 lines
6.6 KiB
C#
Raw Normal View History

2023-08-02 02:36:07 +00:00
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Metal.Effects;
2023-08-03 00:32:59 +00:00
using SharpMetal.ObjectiveCCore;
using SharpMetal.QuartzCore;
using System;
2023-07-28 02:54:24 +00:00
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
2023-07-28 02:54:24 +00:00
[SupportedOSPlatform("macos")]
2023-08-03 18:50:49 +00:00
class Window : IWindow, IDisposable
{
public bool ScreenCaptureRequested { get; set; }
2023-07-28 02:54:24 +00:00
private readonly MetalRenderer _renderer;
2023-08-03 00:32:59 +00:00
private readonly CAMetalLayer _metalLayer;
private int _width;
private int _height;
2024-05-27 22:09:29 +00:00
// private bool _vsyncEnabled;
private AntiAliasing _currentAntiAliasing;
private bool _updateEffect;
private IPostProcessingEffect _effect;
private IScalingFilter _scalingFilter;
private bool _isLinear;
2024-05-27 22:09:29 +00:00
// private float _scalingFilterLevel;
private bool _updateScalingFilter;
private ScalingFilter _currentScalingFilter;
2024-05-27 22:09:29 +00:00
// private bool _colorSpacePassthroughEnabled;
2023-08-03 00:32:59 +00:00
public Window(MetalRenderer renderer, CAMetalLayer metalLayer)
{
2023-07-28 02:54:24 +00:00
_renderer = renderer;
2023-08-03 00:32:59 +00:00
_metalLayer = metalLayer;
}
public void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
{
2023-08-03 00:32:59 +00:00
if (_renderer.Pipeline is Pipeline pipeline && texture is Texture tex)
2023-07-28 02:54:24 +00:00
{
2023-08-03 00:32:59 +00:00
var drawable = new CAMetalDrawable(ObjectiveC.IntPtr_objc_msgSend(_metalLayer, "nextDrawable"));
_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);
2023-07-28 02:54:24 +00:00
}
}
public void SetSize(int width, int height)
{
// Ignore
}
public void ChangeVSyncMode(bool vsyncEnabled)
{
2024-05-27 22:09:29 +00:00
// _vsyncEnabled = vsyncEnabled;
}
public void SetAntiAliasing(AntiAliasing effect)
{
if (_currentAntiAliasing == effect && _effect != null)
{
return;
}
_currentAntiAliasing = effect;
_updateEffect = true;
}
public void SetScalingFilter(ScalingFilter type)
{
if (_currentScalingFilter == type && _effect != null)
{
return;
}
_currentScalingFilter = type;
_updateScalingFilter = true;
}
public void SetScalingFilterLevel(float level)
{
2024-05-27 22:09:29 +00:00
// _scalingFilterLevel = level;
_updateScalingFilter = true;
}
public void SetColorSpacePassthrough(bool colorSpacePassThroughEnabled)
{
2024-05-27 22:09:29 +00:00
// _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:
2024-05-27 22:09:29 +00:00
// 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;
}
}
}
2023-08-12 14:12:35 +00:00
public void Dispose()
{
2024-05-23 18:08:34 +00:00
_metalLayer.Dispose();
}
}
2023-07-28 02:54:24 +00:00
}