mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-07-16 20:26:29 +02:00
Merge Latest Ryujinx (Unstable)
This commit is contained in:
parent
aaefc0a9e5
commit
12ab8bc3e2
1237 changed files with 48656 additions and 21399 deletions
|
@ -30,6 +30,8 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
_thread.Start();
|
||||
}
|
||||
|
||||
public bool HasContext() => _backgroundContext.HasContext();
|
||||
|
||||
private void Run()
|
||||
{
|
||||
InBackground = true;
|
||||
|
|
106
src/Ryujinx.Graphics.OpenGL/Effects/AreaScalingFilter.cs
Normal file
106
src/Ryujinx.Graphics.OpenGL/Effects/AreaScalingFilter.cs
Normal file
|
@ -0,0 +1,106 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.OpenGL.Image;
|
||||
using System;
|
||||
using static Ryujinx.Graphics.OpenGL.Effects.ShaderHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
{
|
||||
internal class AreaScalingFilter : IScalingFilter
|
||||
{
|
||||
private readonly OpenGLRenderer _renderer;
|
||||
private int _inputUniform;
|
||||
private int _outputUniform;
|
||||
private int _srcX0Uniform;
|
||||
private int _srcX1Uniform;
|
||||
private int _srcY0Uniform;
|
||||
private int _scalingShaderProgram;
|
||||
private int _srcY1Uniform;
|
||||
private int _dstX0Uniform;
|
||||
private int _dstX1Uniform;
|
||||
private int _dstY0Uniform;
|
||||
private int _dstY1Uniform;
|
||||
|
||||
public float Level { get; set; }
|
||||
|
||||
public AreaScalingFilter(OpenGLRenderer renderer)
|
||||
{
|
||||
Initialize();
|
||||
|
||||
_renderer = renderer;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_scalingShaderProgram != 0)
|
||||
{
|
||||
GL.DeleteProgram(_scalingShaderProgram);
|
||||
}
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
var scalingShader = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/area_scaling.glsl");
|
||||
|
||||
_scalingShaderProgram = CompileProgram(scalingShader, ShaderType.ComputeShader);
|
||||
|
||||
_inputUniform = GL.GetUniformLocation(_scalingShaderProgram, "Source");
|
||||
_outputUniform = GL.GetUniformLocation(_scalingShaderProgram, "imgOutput");
|
||||
|
||||
_srcX0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcX0");
|
||||
_srcX1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcX1");
|
||||
_srcY0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcY0");
|
||||
_srcY1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcY1");
|
||||
_dstX0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstX0");
|
||||
_dstX1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstX1");
|
||||
_dstY0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstY0");
|
||||
_dstY1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstY1");
|
||||
}
|
||||
|
||||
public void Run(
|
||||
TextureView view,
|
||||
TextureView destinationTexture,
|
||||
int width,
|
||||
int height,
|
||||
Extents2D source,
|
||||
Extents2D destination)
|
||||
{
|
||||
int previousProgram = GL.GetInteger(GetPName.CurrentProgram);
|
||||
int previousUnit = GL.GetInteger(GetPName.ActiveTexture);
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
int previousTextureBinding = GL.GetInteger(GetPName.TextureBinding2D);
|
||||
|
||||
GL.BindImageTexture(0, destinationTexture.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
|
||||
|
||||
int threadGroupWorkRegionDim = 16;
|
||||
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||
|
||||
// Scaling pass
|
||||
GL.UseProgram(_scalingShaderProgram);
|
||||
view.Bind(0);
|
||||
GL.Uniform1(_inputUniform, 0);
|
||||
GL.Uniform1(_outputUniform, 0);
|
||||
GL.Uniform1(_srcX0Uniform, (float)source.X1);
|
||||
GL.Uniform1(_srcX1Uniform, (float)source.X2);
|
||||
GL.Uniform1(_srcY0Uniform, (float)source.Y1);
|
||||
GL.Uniform1(_srcY1Uniform, (float)source.Y2);
|
||||
GL.Uniform1(_dstX0Uniform, (float)destination.X1);
|
||||
GL.Uniform1(_dstX1Uniform, (float)destination.X2);
|
||||
GL.Uniform1(_dstY0Uniform, (float)destination.Y1);
|
||||
GL.Uniform1(_dstY1Uniform, (float)destination.Y2);
|
||||
GL.DispatchCompute(dispatchX, dispatchY, 1);
|
||||
|
||||
GL.UseProgram(previousProgram);
|
||||
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
|
||||
|
||||
(_renderer.Pipeline as Pipeline).RestoreImages1And2();
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding);
|
||||
|
||||
GL.ActiveTexture((TextureUnit)previousUnit);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
|||
private int _srcY0Uniform;
|
||||
private int _scalingShaderProgram;
|
||||
private int _sharpeningShaderProgram;
|
||||
private float _scale = 1;
|
||||
private float _sharpeningLevel = 1;
|
||||
private int _srcY1Uniform;
|
||||
private int _dstX0Uniform;
|
||||
private int _dstX1Uniform;
|
||||
|
@ -30,10 +30,10 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
|||
|
||||
public float Level
|
||||
{
|
||||
get => _scale;
|
||||
get => _sharpeningLevel;
|
||||
set
|
||||
{
|
||||
_scale = MathF.Max(0.01f, value);
|
||||
_sharpeningLevel = MathF.Max(0.01f, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common.Logging;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
{
|
||||
|
@ -6,18 +7,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
|||
{
|
||||
public static int CompileProgram(string shaderCode, ShaderType shaderType)
|
||||
{
|
||||
var shader = GL.CreateShader(shaderType);
|
||||
GL.ShaderSource(shader, shaderCode);
|
||||
GL.CompileShader(shader);
|
||||
|
||||
var program = GL.CreateProgram();
|
||||
GL.AttachShader(program, shader);
|
||||
GL.LinkProgram(program);
|
||||
|
||||
GL.DetachShader(program, shader);
|
||||
GL.DeleteShader(shader);
|
||||
|
||||
return program;
|
||||
return CompileProgram(new string[] { shaderCode }, shaderType);
|
||||
}
|
||||
|
||||
public static int CompileProgram(string[] shaders, ShaderType shaderType)
|
||||
|
@ -26,6 +16,15 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
|||
GL.ShaderSource(shader, shaders.Length, shaders, (int[])null);
|
||||
GL.CompileShader(shader);
|
||||
|
||||
GL.GetShader(shader, ShaderParameter.CompileStatus, out int isCompiled);
|
||||
if (isCompiled == 0)
|
||||
{
|
||||
string log = GL.GetShaderInfoLog(shader);
|
||||
Logger.Error?.Print(LogClass.Gpu, $"Failed to compile effect shader:\n\n{log}\n");
|
||||
GL.DeleteShader(shader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
var program = GL.CreateProgram();
|
||||
GL.AttachShader(program, shader);
|
||||
GL.LinkProgram(program);
|
||||
|
|
119
src/Ryujinx.Graphics.OpenGL/Effects/Shaders/area_scaling.glsl
Normal file
119
src/Ryujinx.Graphics.OpenGL/Effects/Shaders/area_scaling.glsl
Normal file
|
@ -0,0 +1,119 @@
|
|||
#version 430 core
|
||||
precision mediump float;
|
||||
layout (local_size_x = 16, local_size_y = 16) in;
|
||||
layout(rgba8, binding = 0, location=0) uniform image2D imgOutput;
|
||||
layout( location=1 ) uniform sampler2D Source;
|
||||
layout( location=2 ) uniform float srcX0;
|
||||
layout( location=3 ) uniform float srcX1;
|
||||
layout( location=4 ) uniform float srcY0;
|
||||
layout( location=5 ) uniform float srcY1;
|
||||
layout( location=6 ) uniform float dstX0;
|
||||
layout( location=7 ) uniform float dstX1;
|
||||
layout( location=8 ) uniform float dstY0;
|
||||
layout( location=9 ) uniform float dstY1;
|
||||
|
||||
/***** Area Sampling *****/
|
||||
|
||||
// By Sam Belliveau and Filippo Tarpini. Public Domain license.
|
||||
// Effectively a more accurate sharp bilinear filter when upscaling,
|
||||
// that also works as a mathematically perfect downscale filter.
|
||||
// https://entropymine.com/imageworsener/pixelmixing/
|
||||
// https://github.com/obsproject/obs-studio/pull/1715
|
||||
// https://legacy.imagemagick.org/Usage/filter/
|
||||
vec4 AreaSampling(vec2 xy)
|
||||
{
|
||||
// Determine the sizes of the source and target images.
|
||||
vec2 source_size = vec2(abs(srcX1 - srcX0), abs(srcY1 - srcY0));
|
||||
vec2 target_size = vec2(abs(dstX1 - dstX0), abs(dstY1 - dstY0));
|
||||
vec2 inverted_target_size = vec2(1.0) / target_size;
|
||||
|
||||
// Compute the top-left and bottom-right corners of the target pixel box.
|
||||
vec2 t_beg = floor(xy - vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1));
|
||||
vec2 t_end = t_beg + vec2(1.0, 1.0);
|
||||
|
||||
// Convert the target pixel box to source pixel box.
|
||||
vec2 beg = t_beg * inverted_target_size * source_size;
|
||||
vec2 end = t_end * inverted_target_size * source_size;
|
||||
|
||||
// Compute the top-left and bottom-right corners of the pixel box.
|
||||
ivec2 f_beg = ivec2(beg);
|
||||
ivec2 f_end = ivec2(end);
|
||||
|
||||
// Compute how much of the start and end pixels are covered horizontally & vertically.
|
||||
float area_w = 1.0 - fract(beg.x);
|
||||
float area_n = 1.0 - fract(beg.y);
|
||||
float area_e = fract(end.x);
|
||||
float area_s = fract(end.y);
|
||||
|
||||
// Compute the areas of the corner pixels in the pixel box.
|
||||
float area_nw = area_n * area_w;
|
||||
float area_ne = area_n * area_e;
|
||||
float area_sw = area_s * area_w;
|
||||
float area_se = area_s * area_e;
|
||||
|
||||
// Initialize the color accumulator.
|
||||
vec4 avg_color = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
// Accumulate corner pixels.
|
||||
avg_color += area_nw * texelFetch(Source, ivec2(f_beg.x, f_beg.y), 0);
|
||||
avg_color += area_ne * texelFetch(Source, ivec2(f_end.x, f_beg.y), 0);
|
||||
avg_color += area_sw * texelFetch(Source, ivec2(f_beg.x, f_end.y), 0);
|
||||
avg_color += area_se * texelFetch(Source, ivec2(f_end.x, f_end.y), 0);
|
||||
|
||||
// Determine the size of the pixel box.
|
||||
int x_range = int(f_end.x - f_beg.x - 0.5);
|
||||
int y_range = int(f_end.y - f_beg.y - 0.5);
|
||||
|
||||
// Accumulate top and bottom edge pixels.
|
||||
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x)
|
||||
{
|
||||
avg_color += area_n * texelFetch(Source, ivec2(x, f_beg.y), 0);
|
||||
avg_color += area_s * texelFetch(Source, ivec2(x, f_end.y), 0);
|
||||
}
|
||||
|
||||
// Accumulate left and right edge pixels and all the pixels in between.
|
||||
for (int y = f_beg.y + 1; y <= f_beg.y + y_range; ++y)
|
||||
{
|
||||
avg_color += area_w * texelFetch(Source, ivec2(f_beg.x, y), 0);
|
||||
avg_color += area_e * texelFetch(Source, ivec2(f_end.x, y), 0);
|
||||
|
||||
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x)
|
||||
{
|
||||
avg_color += texelFetch(Source, ivec2(x, y), 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the area of the pixel box that was sampled.
|
||||
float area_corners = area_nw + area_ne + area_sw + area_se;
|
||||
float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e);
|
||||
float area_center = float(x_range) * float(y_range);
|
||||
|
||||
// Return the normalized average color.
|
||||
return avg_color / (area_corners + area_edges + area_center);
|
||||
}
|
||||
|
||||
float insideBox(vec2 v, vec2 bLeft, vec2 tRight) {
|
||||
vec2 s = step(bLeft, v) - step(tRight, v);
|
||||
return s.x * s.y;
|
||||
}
|
||||
|
||||
vec2 translateDest(vec2 pos) {
|
||||
vec2 translatedPos = vec2(pos.x, pos.y);
|
||||
translatedPos.x = dstX1 < dstX0 ? dstX1 - translatedPos.x : translatedPos.x;
|
||||
translatedPos.y = dstY0 > dstY1 ? dstY0 + dstY1 - translatedPos.y - 1 : translatedPos.y;
|
||||
return translatedPos;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 bLeft = vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1);
|
||||
vec2 tRight = vec2(dstX1 > dstX0 ? dstX1 : dstX0, dstY1 > dstY0 ? dstY1 : dstY0);
|
||||
ivec2 loc = ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y);
|
||||
if (insideBox(loc, bLeft, tRight) == 0) {
|
||||
imageStore(imgOutput, loc, vec4(0, 0, 0, 1));
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 outColor = AreaSampling(loc);
|
||||
imageStore(imgOutput, ivec2(translateDest(loc)), vec4(outColor.rgb, 1));
|
||||
}
|
|
@ -85,4 +85,4 @@ void main() {
|
|||
CurrFilter(gxy);
|
||||
gxy.x -= 8u;
|
||||
CurrFilter(gxy);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,8 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
|
|||
|
||||
public int Quality
|
||||
{
|
||||
get => _quality; set
|
||||
get => _quality;
|
||||
set
|
||||
{
|
||||
_quality = Math.Clamp(value, 0, _qualities.Length - 1);
|
||||
}
|
||||
|
@ -150,8 +151,8 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
|
|||
_areaTexture = new TextureStorage(_renderer, areaInfo);
|
||||
_searchTexture = new TextureStorage(_renderer, searchInfo);
|
||||
|
||||
var areaTexture = EmbeddedResources.Read("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaAreaTexture.bin");
|
||||
var searchTexture = EmbeddedResources.Read("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaSearchTexture.bin");
|
||||
var areaTexture = EmbeddedResources.ReadFileToRentedMemory("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaAreaTexture.bin");
|
||||
var searchTexture = EmbeddedResources.ReadFileToRentedMemory("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaSearchTexture.bin");
|
||||
|
||||
var areaView = _areaTexture.CreateDefaultView();
|
||||
var searchView = _searchTexture.CreateDefaultView();
|
||||
|
|
|
@ -68,6 +68,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
Add(Format.S8Uint, new FormatInfo(1, false, false, All.StencilIndex8, PixelFormat.StencilIndex, PixelType.UnsignedByte));
|
||||
Add(Format.D16Unorm, new FormatInfo(1, false, false, All.DepthComponent16, PixelFormat.DepthComponent, PixelType.UnsignedShort));
|
||||
Add(Format.S8UintD24Unorm, new FormatInfo(1, false, false, All.Depth24Stencil8, PixelFormat.DepthStencil, PixelType.UnsignedInt248));
|
||||
Add(Format.X8UintD24Unorm, new FormatInfo(1, false, false, All.DepthComponent24, PixelFormat.DepthComponent, PixelType.UnsignedInt));
|
||||
Add(Format.D32Float, new FormatInfo(1, false, false, All.DepthComponent32f, PixelFormat.DepthComponent, PixelType.Float));
|
||||
Add(Format.D24UnormS8Uint, new FormatInfo(1, false, false, All.Depth24Stencil8, PixelFormat.DepthStencil, PixelType.UnsignedInt248));
|
||||
Add(Format.D32FloatS8Uint, new FormatInfo(1, false, false, All.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev));
|
||||
|
@ -161,6 +162,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
Add(Format.A1B5G5R5Unorm, new FormatInfo(4, true, false, All.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551));
|
||||
Add(Format.B8G8R8A8Unorm, new FormatInfo(4, true, false, All.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte));
|
||||
Add(Format.B8G8R8A8Srgb, new FormatInfo(4, false, false, All.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte));
|
||||
Add(Format.B10G10R10A2Unorm, new FormatInfo(4, false, false, All.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed));
|
||||
|
||||
Add(Format.R8Unorm, SizedInternalFormat.R8);
|
||||
Add(Format.R8Uint, SizedInternalFormat.R8ui);
|
||||
|
@ -223,5 +225,17 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
{
|
||||
return _tableImage[(int)format];
|
||||
}
|
||||
|
||||
public static bool IsPackedDepthStencil(Format format)
|
||||
{
|
||||
return format == Format.D24UnormS8Uint ||
|
||||
format == Format.D32FloatS8Uint ||
|
||||
format == Format.S8UintD24Unorm;
|
||||
}
|
||||
|
||||
public static bool IsDepthOnly(Format format)
|
||||
{
|
||||
return format == Format.D16Unorm || format == Format.D32Float || format == Format.X8UintD24Unorm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,11 +119,11 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
private static FramebufferAttachment GetAttachment(Format format)
|
||||
{
|
||||
if (IsPackedDepthStencilFormat(format))
|
||||
if (FormatTable.IsPackedDepthStencil(format))
|
||||
{
|
||||
return FramebufferAttachment.DepthStencilAttachment;
|
||||
}
|
||||
else if (IsDepthOnlyFormat(format))
|
||||
else if (FormatTable.IsDepthOnly(format))
|
||||
{
|
||||
return FramebufferAttachment.DepthAttachment;
|
||||
}
|
||||
|
@ -133,18 +133,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
private static bool IsPackedDepthStencilFormat(Format format)
|
||||
{
|
||||
return format == Format.D24UnormS8Uint ||
|
||||
format == Format.D32FloatS8Uint ||
|
||||
format == Format.S8UintD24Unorm;
|
||||
}
|
||||
|
||||
private static bool IsDepthOnlyFormat(Format format)
|
||||
{
|
||||
return format == Format.D16Unorm || format == Format.D32Float;
|
||||
}
|
||||
|
||||
public int GetColorLayerCount(int index)
|
||||
{
|
||||
return _colors[index]?.Info.GetDepthOrLayers() ?? 0;
|
||||
|
|
|
@ -7,21 +7,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
{
|
||||
void MakeCurrent();
|
||||
|
||||
// TODO: Support more APIs per platform.
|
||||
static bool HasContext()
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
return WGLHelper.GetCurrentContext() != IntPtr.Zero;
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
return GLXHelper.GetCurrentContext() != IntPtr.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool HasContext();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -8,9 +9,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
{
|
||||
static class FormatConverter
|
||||
{
|
||||
public unsafe static byte[] ConvertS8D24ToD24S8(ReadOnlySpan<byte> data)
|
||||
public unsafe static MemoryOwner<byte> ConvertS8D24ToD24S8(ReadOnlySpan<byte> data)
|
||||
{
|
||||
byte[] output = new byte[data.Length];
|
||||
MemoryOwner<byte> outputMemory = MemoryOwner<byte>.Rent(data.Length);
|
||||
|
||||
Span<byte> output = outputMemory.Span;
|
||||
|
||||
int start = 0;
|
||||
|
||||
|
@ -74,7 +77,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
outSpan[i] = BitOperations.RotateLeft(dataSpan[i], 8);
|
||||
}
|
||||
|
||||
return output;
|
||||
return outputMemory;
|
||||
}
|
||||
|
||||
public unsafe static byte[] ConvertD24S8ToS8D24(ReadOnlySpan<byte> data)
|
||||
|
|
63
src/Ryujinx.Graphics.OpenGL/Image/ImageArray.cs
Normal file
63
src/Ryujinx.Graphics.OpenGL/Image/ImageArray.cs
Normal file
|
@ -0,0 +1,63 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL.Image
|
||||
{
|
||||
class ImageArray : IImageArray
|
||||
{
|
||||
private record struct TextureRef
|
||||
{
|
||||
public int Handle;
|
||||
public Format Format;
|
||||
}
|
||||
|
||||
private readonly TextureRef[] _images;
|
||||
|
||||
public ImageArray(int size)
|
||||
{
|
||||
_images = new TextureRef[size];
|
||||
}
|
||||
|
||||
public void SetImages(int index, ITexture[] images)
|
||||
{
|
||||
for (int i = 0; i < images.Length; i++)
|
||||
{
|
||||
ITexture image = images[i];
|
||||
|
||||
if (image is TextureBase imageBase)
|
||||
{
|
||||
_images[index + i].Handle = imageBase.Handle;
|
||||
_images[index + i].Format = imageBase.Format;
|
||||
}
|
||||
else
|
||||
{
|
||||
_images[index + i].Handle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Bind(int baseBinding)
|
||||
{
|
||||
for (int i = 0; i < _images.Length; i++)
|
||||
{
|
||||
if (_images[i].Handle == 0)
|
||||
{
|
||||
GL.BindImageTexture(baseBinding + i, 0, 0, true, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
|
||||
}
|
||||
else
|
||||
{
|
||||
SizedInternalFormat format = FormatTable.GetImageFormat(_images[i].Format);
|
||||
|
||||
if (format != 0)
|
||||
{
|
||||
GL.BindImageTexture(baseBinding + i, _images[i].Handle, 0, true, 0, TextureAccess.ReadWrite, format);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
56
src/Ryujinx.Graphics.OpenGL/Image/TextureArray.cs
Normal file
56
src/Ryujinx.Graphics.OpenGL/Image/TextureArray.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL.Image
|
||||
{
|
||||
class TextureArray : ITextureArray
|
||||
{
|
||||
private record struct TextureRef
|
||||
{
|
||||
public TextureBase Texture;
|
||||
public Sampler Sampler;
|
||||
}
|
||||
|
||||
private readonly TextureRef[] _textureRefs;
|
||||
|
||||
public TextureArray(int size)
|
||||
{
|
||||
_textureRefs = new TextureRef[size];
|
||||
}
|
||||
|
||||
public void SetSamplers(int index, ISampler[] samplers)
|
||||
{
|
||||
for (int i = 0; i < samplers.Length; i++)
|
||||
{
|
||||
_textureRefs[index + i].Sampler = samplers[i] as Sampler;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTextures(int index, ITexture[] textures)
|
||||
{
|
||||
for (int i = 0; i < textures.Length; i++)
|
||||
{
|
||||
_textureRefs[index + i].Texture = textures[i] as TextureBase;
|
||||
}
|
||||
}
|
||||
|
||||
public void Bind(int baseBinding)
|
||||
{
|
||||
for (int i = 0; i < _textureRefs.Length; i++)
|
||||
{
|
||||
if (_textureRefs[i].Texture != null)
|
||||
{
|
||||
_textureRefs[i].Texture.Bind(baseBinding + i);
|
||||
_textureRefs[i].Sampler?.Bind(baseBinding + i);
|
||||
}
|
||||
else
|
||||
{
|
||||
TextureBase.ClearBinding(baseBinding + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -55,22 +55,25 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetData(IMemoryOwner<byte> data)
|
||||
/// <inheritdoc/>
|
||||
public void SetData(MemoryOwner<byte> data)
|
||||
{
|
||||
var dataSpan = data.Memory.Span;
|
||||
var dataSpan = data.Span;
|
||||
|
||||
Buffer.SetData(_buffer, _bufferOffset, dataSpan[..Math.Min(dataSpan.Length, _bufferSize)]);
|
||||
|
||||
data.Dispose();
|
||||
}
|
||||
|
||||
public void SetData(IMemoryOwner<byte> data, int layer, int level)
|
||||
/// <inheritdoc/>
|
||||
public void SetData(MemoryOwner<byte> data, int layer, int level)
|
||||
{
|
||||
data.Dispose();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
|
||||
/// <inheritdoc/>
|
||||
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
|
||||
{
|
||||
data.Dispose();
|
||||
throw new NotSupportedException();
|
||||
|
|
|
@ -294,7 +294,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
{
|
||||
return FramebufferAttachment.DepthStencilAttachment;
|
||||
}
|
||||
else if (IsDepthOnly(format))
|
||||
else if (FormatTable.IsDepthOnly(format))
|
||||
{
|
||||
return FramebufferAttachment.DepthAttachment;
|
||||
}
|
||||
|
@ -324,11 +324,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
|
||||
private static ClearBufferMask GetMask(Format format)
|
||||
{
|
||||
if (format == Format.D24UnormS8Uint || format == Format.D32FloatS8Uint || format == Format.S8UintD24Unorm)
|
||||
if (FormatTable.IsPackedDepthStencil(format))
|
||||
{
|
||||
return ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit;
|
||||
}
|
||||
else if (IsDepthOnly(format))
|
||||
else if (FormatTable.IsDepthOnly(format))
|
||||
{
|
||||
return ClearBufferMask.DepthBufferBit;
|
||||
}
|
||||
|
@ -342,11 +342,6 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
}
|
||||
}
|
||||
|
||||
private static bool IsDepthOnly(Format format)
|
||||
{
|
||||
return format == Format.D16Unorm || format == Format.D32Float;
|
||||
}
|
||||
|
||||
public TextureView BgraSwap(TextureView from)
|
||||
{
|
||||
TextureView to = (TextureView)_renderer.CreateTexture(from.Info);
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
internalFormat = (SizedInternalFormat)format.PixelInternalFormat;
|
||||
}
|
||||
|
||||
int levels = Info.GetLevelsClamped();
|
||||
int levels = Info.Levels;
|
||||
|
||||
switch (Info.Target)
|
||||
{
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
pixelInternalFormat = format.PixelInternalFormat;
|
||||
}
|
||||
|
||||
int levels = Info.GetLevelsClamped();
|
||||
int levels = Info.Levels;
|
||||
|
||||
GL.TextureView(
|
||||
Handle,
|
||||
|
@ -268,7 +268,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
public unsafe PinnedSpan<byte> GetData()
|
||||
{
|
||||
int size = 0;
|
||||
int levels = Info.GetLevelsClamped();
|
||||
int levels = Info.Levels;
|
||||
|
||||
for (int level = 0; level < levels; level++)
|
||||
{
|
||||
|
@ -427,7 +427,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
faces = 6;
|
||||
}
|
||||
|
||||
int levels = Info.GetLevelsClamped();
|
||||
int levels = Info.Levels;
|
||||
|
||||
for (int level = 0; level < levels; level++)
|
||||
{
|
||||
|
@ -449,77 +449,61 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
}
|
||||
}
|
||||
|
||||
public void SetData(ReadOnlySpan<byte> dataSpan)
|
||||
public void SetData(MemoryOwner<byte> data)
|
||||
{
|
||||
if (Format == Format.S8UintD24Unorm)
|
||||
using (data = EnsureDataFormat(data))
|
||||
{
|
||||
dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* ptr = dataSpan)
|
||||
unsafe
|
||||
{
|
||||
ReadFrom((IntPtr)ptr, dataSpan.Length);
|
||||
var dataSpan = data.Span;
|
||||
fixed (byte* ptr = dataSpan)
|
||||
{
|
||||
ReadFrom((IntPtr)ptr, dataSpan.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetData(IMemoryOwner<byte> data)
|
||||
public void SetData(MemoryOwner<byte> data, int layer, int level)
|
||||
{
|
||||
SetData(data.Memory.Span);
|
||||
|
||||
data.Dispose();
|
||||
}
|
||||
|
||||
public void SetData(IMemoryOwner<byte> data, int layer, int level)
|
||||
{
|
||||
var dataSpan = data.Memory.Span;
|
||||
|
||||
if (Format == Format.S8UintD24Unorm)
|
||||
using (data = EnsureDataFormat(data))
|
||||
{
|
||||
dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* ptr = dataSpan)
|
||||
unsafe
|
||||
{
|
||||
int width = Math.Max(Info.Width >> level, 1);
|
||||
int height = Math.Max(Info.Height >> level, 1);
|
||||
fixed (byte* ptr = data.Span)
|
||||
{
|
||||
int width = Math.Max(Info.Width >> level, 1);
|
||||
int height = Math.Max(Info.Height >> level, 1);
|
||||
|
||||
ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height);
|
||||
ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data.Dispose();
|
||||
}
|
||||
|
||||
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
|
||||
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
|
||||
{
|
||||
var dataSpan = data.Memory.Span;
|
||||
|
||||
if (Format == Format.S8UintD24Unorm)
|
||||
using (data = EnsureDataFormat(data))
|
||||
{
|
||||
dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
|
||||
}
|
||||
int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
|
||||
int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight);
|
||||
|
||||
int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
|
||||
int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight);
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* ptr = dataSpan)
|
||||
unsafe
|
||||
{
|
||||
ReadFrom2D(
|
||||
(IntPtr)ptr,
|
||||
layer,
|
||||
level,
|
||||
region.X,
|
||||
region.Y,
|
||||
region.Width,
|
||||
region.Height,
|
||||
BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks);
|
||||
fixed (byte* ptr = data.Span)
|
||||
{
|
||||
ReadFrom2D(
|
||||
(IntPtr)ptr,
|
||||
layer,
|
||||
level,
|
||||
region.X,
|
||||
region.Y,
|
||||
region.Width,
|
||||
region.Height,
|
||||
BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -543,6 +527,19 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
ReadFrom2D(data, layer, level, x, y, width, height, mipSize);
|
||||
}
|
||||
|
||||
private MemoryOwner<byte> EnsureDataFormat(MemoryOwner<byte> data)
|
||||
{
|
||||
if (Format == Format.S8UintD24Unorm)
|
||||
{
|
||||
using (data)
|
||||
{
|
||||
return FormatConverter.ConvertS8D24ToD24S8(data.Span);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height, int mipSize)
|
||||
{
|
||||
TextureTarget target = Target.Convert();
|
||||
|
@ -724,7 +721,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
int width = Info.Width;
|
||||
int height = Info.Height;
|
||||
int depth = Info.Depth;
|
||||
int levels = Info.GetLevelsClamped();
|
||||
int levels = Info.Levels;
|
||||
|
||||
int offset = 0;
|
||||
|
||||
|
|
|
@ -61,7 +61,9 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
{
|
||||
BufferCount++;
|
||||
|
||||
if (access.HasFlag(GAL.BufferAccess.FlushPersistent))
|
||||
var memType = access & GAL.BufferAccess.MemoryTypeMask;
|
||||
|
||||
if (memType == GAL.BufferAccess.HostMemory)
|
||||
{
|
||||
BufferHandle handle = Buffer.CreatePersistent(size);
|
||||
|
||||
|
@ -75,11 +77,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
public BufferHandle CreateBuffer(int size, GAL.BufferAccess access, BufferHandle storageHint)
|
||||
{
|
||||
return CreateBuffer(size, access);
|
||||
}
|
||||
|
||||
public BufferHandle CreateBuffer(nint pointer, int size)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
|
@ -90,6 +87,11 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public IImageArray CreateImageArray(int size, bool isBuffer)
|
||||
{
|
||||
return new ImageArray(size);
|
||||
}
|
||||
|
||||
public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info)
|
||||
{
|
||||
return new Program(shaders, info.FragmentOutputMap);
|
||||
|
@ -112,6 +114,11 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
public ITextureArray CreateTextureArray(int size, bool isBuffer)
|
||||
{
|
||||
return new TextureArray(size);
|
||||
}
|
||||
|
||||
public void DeleteBuffer(BufferHandle buffer)
|
||||
{
|
||||
PersistentBuffers.Unmap(buffer);
|
||||
|
@ -121,7 +128,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
public HardwareInfo GetHardwareInfo()
|
||||
{
|
||||
return new HardwareInfo(GpuVendor, GpuRenderer);
|
||||
return new HardwareInfo(GpuVendor, GpuRenderer, GpuVendor); // OpenGL does not provide a driver name, vendor name is closest analogue.
|
||||
}
|
||||
|
||||
public PinnedSpan<byte> GetBufferData(BufferHandle buffer, int offset, int size)
|
||||
|
@ -138,6 +145,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
return new Capabilities(
|
||||
api: TargetApi.OpenGL,
|
||||
vendorName: GpuVendor,
|
||||
memoryType: SystemMemoryType.BackendManaged,
|
||||
hasFrontFacingBug: intelWindows,
|
||||
hasVectorIndexingBug: amdWindows,
|
||||
needsFragmentOutputSpecialization: false,
|
||||
|
@ -151,6 +159,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
supportsBgraFormat: false,
|
||||
supportsR4G4Format: false,
|
||||
supportsR4G4B4A4Format: true,
|
||||
supportsScaledVertexFormats: true,
|
||||
supportsSnormBufferTextureFormat: false,
|
||||
supports5BitComponentFormat: true,
|
||||
supportsSparseBuffer: false,
|
||||
|
@ -165,7 +174,8 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
supportsMismatchingViewFormat: HwCapabilities.SupportsMismatchingViewFormat,
|
||||
supportsCubemapView: true,
|
||||
supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
|
||||
supportsScaledVertexFormats: true,
|
||||
supportsQuads: HwCapabilities.SupportsQuads,
|
||||
supportsSeparateSampler: false,
|
||||
supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
|
||||
supportsShaderBarrierDivergence: !(intelWindows || intelUnix),
|
||||
supportsShaderFloat64: true,
|
||||
|
@ -177,6 +187,12 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
|
||||
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
|
||||
supportsDepthClipControl: true,
|
||||
uniformBufferSetIndex: 0,
|
||||
storageBufferSetIndex: 1,
|
||||
textureSetIndex: 2,
|
||||
imageSetIndex: 3,
|
||||
extraSetBaseIndex: 0,
|
||||
maximumExtraSets: 0,
|
||||
maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?
|
||||
maximumStorageBuffersPerStage: 16,
|
||||
maximumTexturesPerStage: 32,
|
||||
|
@ -186,7 +202,8 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
shaderSubgroupSize: Constants.MaxSubgroupSize,
|
||||
storageBufferOffsetAlignment: HwCapabilities.StorageBufferOffsetAlignment,
|
||||
textureBufferOffsetAlignment: HwCapabilities.TextureBufferOffsetAlignment,
|
||||
gatherBiasPrecision: intelWindows || amdWindows ? 8 : 0); // Precision is 8 for these vendors on Vulkan.
|
||||
gatherBiasPrecision: intelWindows || amdWindows ? 8 : 0, // Precision is 8 for these vendors on Vulkan.
|
||||
maximumGpuMemory: 0);
|
||||
}
|
||||
|
||||
public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)
|
||||
|
@ -248,7 +265,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
{
|
||||
// alwaysBackground is ignored, since we cannot switch from the current context.
|
||||
|
||||
if (IOpenGLContext.HasContext())
|
||||
if (_window.BackgroundContext.HasContext())
|
||||
{
|
||||
action(); // We have a context already - use that (assuming it is the main one).
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
private readonly Vector4<int>[] _fpIsBgra = new Vector4<int>[SupportBuffer.FragmentIsBgraCount];
|
||||
|
||||
private readonly (TextureBase, Format)[] _images;
|
||||
private readonly TextureBase[] _images;
|
||||
private TextureBase _unit0Texture;
|
||||
private Sampler _unit0Sampler;
|
||||
|
||||
|
@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
_fragmentOutputMap = uint.MaxValue;
|
||||
_componentMasks = uint.MaxValue;
|
||||
|
||||
_images = new (TextureBase, Format)[SavedImages];
|
||||
_images = new TextureBase[SavedImages];
|
||||
|
||||
_tfbs = new BufferHandle[Constants.MaxTransformFeedbackBuffers];
|
||||
_tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers];
|
||||
|
@ -935,11 +935,11 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
SetFrontFace(_frontFace = frontFace.Convert());
|
||||
}
|
||||
|
||||
public void SetImage(int binding, ITexture texture, Format imageFormat)
|
||||
public void SetImage(ShaderStage stage, int binding, ITexture texture)
|
||||
{
|
||||
if ((uint)binding < SavedImages)
|
||||
{
|
||||
_images[binding] = (texture as TextureBase, imageFormat);
|
||||
_images[binding] = texture as TextureBase;
|
||||
}
|
||||
|
||||
if (texture == null)
|
||||
|
@ -950,7 +950,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
TextureBase texBase = (TextureBase)texture;
|
||||
|
||||
SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat);
|
||||
SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format);
|
||||
|
||||
if (format != 0)
|
||||
{
|
||||
|
@ -958,6 +958,16 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
public void SetImageArray(ShaderStage stage, int binding, IImageArray array)
|
||||
{
|
||||
(array as ImageArray).Bind(binding);
|
||||
}
|
||||
|
||||
public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
|
||||
{
|
||||
throw new NotSupportedException("OpenGL does not support descriptor sets.");
|
||||
}
|
||||
|
||||
public void SetIndexBuffer(BufferRange buffer, IndexType type)
|
||||
{
|
||||
_elementsType = type.Convert();
|
||||
|
@ -1117,7 +1127,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
prg.Bind();
|
||||
}
|
||||
|
||||
if (prg.HasFragmentShader && _fragmentOutputMap != (uint)prg.FragmentOutputMap)
|
||||
if (_fragmentOutputMap != (uint)prg.FragmentOutputMap)
|
||||
{
|
||||
_fragmentOutputMap = (uint)prg.FragmentOutputMap;
|
||||
|
||||
|
@ -1302,6 +1312,15 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
public void SetTextureArray(ShaderStage stage, int binding, ITextureArray array)
|
||||
{
|
||||
(array as TextureArray).Bind(binding);
|
||||
}
|
||||
|
||||
public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
|
||||
{
|
||||
throw new NotSupportedException("OpenGL does not support descriptor sets.");
|
||||
}
|
||||
|
||||
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
|
||||
{
|
||||
|
@ -1603,11 +1622,11 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
{
|
||||
for (int i = 0; i < SavedImages; i++)
|
||||
{
|
||||
(TextureBase texBase, Format imageFormat) = _images[i];
|
||||
TextureBase texBase = _images[i];
|
||||
|
||||
if (texBase != null)
|
||||
{
|
||||
SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat);
|
||||
SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format);
|
||||
|
||||
if (format != 0)
|
||||
{
|
||||
|
|
|
@ -30,7 +30,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete;
|
||||
private int[] _shaderHandles;
|
||||
|
||||
public bool HasFragmentShader;
|
||||
public int FragmentOutputMap { get; }
|
||||
|
||||
public Program(ShaderSource[] shaders, int fragmentOutputMap)
|
||||
|
@ -40,6 +39,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
GL.ProgramParameter(Handle, ProgramParameterName.ProgramBinaryRetrievableHint, 1);
|
||||
|
||||
_shaderHandles = new int[shaders.Length];
|
||||
bool hasFragmentShader = false;
|
||||
|
||||
for (int index = 0; index < shaders.Length; index++)
|
||||
{
|
||||
|
@ -47,7 +47,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
if (shader.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
HasFragmentShader = true;
|
||||
hasFragmentShader = true;
|
||||
}
|
||||
|
||||
int shaderHandle = GL.CreateShader(shader.Stage.Convert());
|
||||
|
@ -71,7 +71,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
GL.LinkProgram(Handle);
|
||||
|
||||
FragmentOutputMap = fragmentOutputMap;
|
||||
FragmentOutputMap = hasFragmentShader ? fragmentOutputMap : 0;
|
||||
}
|
||||
|
||||
public Program(ReadOnlySpan<byte> code, bool hasFragmentShader, int fragmentOutputMap)
|
||||
|
@ -91,8 +91,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
HasFragmentShader = hasFragmentShader;
|
||||
FragmentOutputMap = fragmentOutputMap;
|
||||
FragmentOutputMap = hasFragmentShader ? fragmentOutputMap : 0;
|
||||
}
|
||||
|
||||
public void Bind()
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<EmbeddedResource Include="Effects\Shaders\ffx_fsr1.h" />
|
||||
<EmbeddedResource Include="Effects\Shaders\ffx_a.h" />
|
||||
<EmbeddedResource Include="Effects\Shaders\fsr_scaling.glsl" />
|
||||
<EmbeddedResource Include="Effects\Shaders\area_scaling.glsl" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -373,6 +373,16 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
_isLinear = false;
|
||||
_scalingFilter.Level = _scalingFilterLevel;
|
||||
|
||||
RecreateUpscalingTexture();
|
||||
break;
|
||||
case ScalingFilter.Area:
|
||||
if (_scalingFilter is not AreaScalingFilter)
|
||||
{
|
||||
_scalingFilter?.Dispose();
|
||||
_scalingFilter = new AreaScalingFilter(_renderer);
|
||||
}
|
||||
_isLinear = false;
|
||||
|
||||
RecreateUpscalingTexture();
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue