2023-08-02 02:36:07 +00:00
|
|
|
using Ryujinx.Common.Logging;
|
2024-08-31 20:42:56 +00:00
|
|
|
using Ryujinx.Graphics.GAL;
|
2024-05-27 13:47:50 +00:00
|
|
|
using Ryujinx.Graphics.Metal.Effects;
|
2023-08-03 00:32:59 +00:00
|
|
|
using SharpMetal.ObjectiveCCore;
|
|
|
|
using SharpMetal.QuartzCore;
|
2024-08-31 20:42:56 +00:00
|
|
|
using System;
|
2023-07-28 02:54:24 +00:00
|
|
|
using System.Runtime.Versioning;
|
2024-08-31 20:42:56 +00:00
|
|
|
|
|
|
|
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
|
2024-08-31 20:42:56 +00:00
|
|
|
{
|
2024-05-27 13:47:50 +00:00
|
|
|
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;
|
2024-08-31 20:42:56 +00:00
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
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;
|
|
|
|
|
2023-08-03 00:32:59 +00:00
|
|
|
public Window(MetalRenderer renderer, CAMetalLayer metalLayer)
|
2024-08-31 20:42:56 +00:00
|
|
|
{
|
2023-07-28 02:54:24 +00:00
|
|
|
_renderer = renderer;
|
2023-08-03 00:32:59 +00:00
|
|
|
_metalLayer = metalLayer;
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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"));
|
2024-05-27 13:47:50 +00:00
|
|
|
|
|
|
|
_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
|
|
|
}
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SetSize(int width, int height)
|
|
|
|
{
|
2024-05-27 13:47:50 +00:00
|
|
|
// Ignore
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void ChangeVSyncMode(bool vsyncEnabled)
|
|
|
|
{
|
2024-05-27 13:47:50 +00:00
|
|
|
_vsyncEnabled = vsyncEnabled;
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
public void SetAntiAliasing(AntiAliasing effect)
|
2024-08-31 20:42:56 +00:00
|
|
|
{
|
2024-05-27 13:47:50 +00:00
|
|
|
if (_currentAntiAliasing == effect && _effect != null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_currentAntiAliasing = effect;
|
|
|
|
|
|
|
|
_updateEffect = true;
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SetScalingFilter(ScalingFilter type)
|
|
|
|
{
|
2024-05-27 13:47:50 +00:00
|
|
|
if (_currentScalingFilter == type && _effect != null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_currentScalingFilter = type;
|
|
|
|
|
|
|
|
_updateScalingFilter = true;
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SetScalingFilterLevel(float level)
|
|
|
|
{
|
2024-05-27 13:47:50 +00:00
|
|
|
_scalingFilterLevel = level;
|
|
|
|
_updateScalingFilter = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetColorSpacePassthrough(bool colorSpacePassThroughEnabled)
|
|
|
|
{
|
|
|
|
_colorSpacePassthroughEnabled = colorSpacePassThroughEnabled;
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
2024-05-27 13:47:50 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-08-12 14:12:35 +00:00
|
|
|
|
2024-08-31 20:42:56 +00:00
|
|
|
public void Dispose()
|
|
|
|
{
|
2024-05-23 18:08:34 +00:00
|
|
|
_metalLayer.Dispose();
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-28 02:54:24 +00:00
|
|
|
}
|