Compare commits

...

12 commits

Author SHA1 Message Date
Isaac Marovitz 6e9024b7ed
Merge e584f8d37d into a23d8cb92f 2024-05-10 01:22:43 +00:00
Isaac Marovitz e584f8d37d
Ava Working? 2024-05-09 21:22:38 -04:00
Isaac Marovitz 5db3568305
OpenGL namespace is all done! 2024-05-09 21:13:22 -04:00
Isaac Marovitz 15978d9c55
Pipeline 2024-05-09 20:28:46 -04:00
Isaac Marovitz 0c88c23b30
Debugger, Pipeline 2024-05-09 20:04:29 -04:00
Isaac Marovitz 1d18ed2ba2
Program 2024-05-09 19:44:22 -04:00
Isaac Marovitz a9d0dd3893
Convert GetBinary 2024-05-09 19:34:19 -04:00
Isaac Marovitz 8df23211f6
Effects 2024-05-09 19:21:01 -04:00
Isaac Marovitz e46b671875
Cleanup IntPtr casts 2024-05-09 19:16:26 -04:00
Isaac Marovitz 38d900c932
PersistentBuffers & Sync 2024-05-09 19:13:37 -04:00
Isaac Marovitz 740842d600
TextureView 2024-05-09 19:00:02 -04:00
Isaac Marovitz 65abc70edc
Almost there 2024-05-09 16:32:14 -04:00
26 changed files with 751 additions and 625 deletions

View file

@ -39,6 +39,7 @@
<PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Silk.NET.OpenGL.Legacy" Version="2.21.0" />
<PackageVersion Include="Silk.NET.OpenGL.Legacy.Extensions.ARB" Version="2.21.0" />
<PackageVersion Include="Silk.NET.OpenGL.Legacy.Extensions.EXT" Version="2.21.0" />
<PackageVersion Include="Silk.NET.OpenGL.Legacy.Extensions.NV" Version="2.21.0" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />

View file

@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.OpenGL
{
return new PinnedSpan<byte>(IntPtr.Add(ptr, offset).ToPointer(), size);
}
else if (HwCapabilities.UsePersistentBufferForFlush)
else if (gd.Capabilities.UsePersistentBufferForFlush)
{
return PinnedSpan<byte>.UnsafeFromSpan(gd.PersistentBuffers.Default.GetBufferData(buffer, offset, size));
}

View file

@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.OpenGL
public static void Initialize(GL gl, GraphicsDebugLevel logLevel)
{
// Disable everything
gl.DebugMessageControl(DebugSource.DontCare, DebugType.DontCare, DebugSeverity.DontCare, 0, (int[])null, false);
gl.DebugMessageControl(DebugSource.DontCare, DebugType.DontCare, DebugSeverity.DontCare, 0, (uint[])null, false);
if (logLevel == GraphicsDebugLevel.None)
{
@ -30,16 +30,16 @@ namespace Ryujinx.Graphics.OpenGL
if (logLevel == GraphicsDebugLevel.Error)
{
gl.DebugMessageControl(DebugSource.DontCare, DebugType.DebugTypeError, DebugSeverity.DontCare, 0, (int[])null, true);
gl.DebugMessageControl(DebugSource.DontCare, DebugType.DebugTypeError, DebugSeverity.DontCare, 0, (uint[])null, true);
}
else if (logLevel == GraphicsDebugLevel.Slowdowns)
{
gl.DebugMessageControl(DebugSource.DontCare, DebugType.DebugTypeError, DebugSeverity.DontCare, 0, (int[])null, true);
gl.DebugMessageControl(DebugSource.DontCare, DebugType.DebugTypePerformance, DebugSeverity.DontCare, 0, (int[])null, true);
gl.DebugMessageControl(DebugSource.DontCare, DebugType.DebugTypeError, DebugSeverity.DontCare, 0, (uint[])null, true);
gl.DebugMessageControl(DebugSource.DontCare, DebugType.DebugTypePerformance, DebugSeverity.DontCare, 0, (uint[])null, true);
}
else
{
gl.DebugMessageControl(DebugSource.DontCare, DebugType.DontCare, DebugSeverity.DontCare, 0, (int[])null, true);
gl.DebugMessageControl(DebugSource.DontCare, DebugType.DontCare, DebugSeverity.DontCare, 0, (uint[])null, true);
}
_counter = 0;
@ -61,7 +61,10 @@ namespace Ryujinx.Graphics.OpenGL
{
string msg = Marshal.PtrToStringUTF8(message).Replace('\n', ' ');
switch (type)
DebugType debugType = (DebugType)type;
DebugSource debugSource = (DebugSource)source;
switch (debugType)
{
case DebugType.DebugTypeError:
Logger.Error?.Print(LogClass.Gpu, $"{severity}: {msg}\nCallStack={Environment.StackTrace}", "GLERROR");
@ -76,7 +79,7 @@ namespace Ryujinx.Graphics.OpenGL
Logger.Info?.Print(LogClass.Gpu, $"}} ({id}) {severity}: {msg}", "GLINFO");
break;
default:
if (source == DebugSource.DebugSourceApplication)
if (debugSource == DebugSource.DebugSourceApplication)
{
Logger.Info?.Print(LogClass.Gpu, $"{type} {severity}: {msg}", "GLINFO");
}
@ -93,7 +96,7 @@ namespace Ryujinx.Graphics.OpenGL
{
int counter = Interlocked.Increment(ref _counter);
gl.PushDebugGroup(DebugSource.DebugSourceApplication, counter, dbgMsg.Length, dbgMsg);
gl.PushDebugGroup(DebugSource.DebugSourceApplication, (uint)counter, (uint)dbgMsg.Length, dbgMsg);
}
public static void PopGroup(GL gl)
@ -103,7 +106,7 @@ namespace Ryujinx.Graphics.OpenGL
public static void Print(GL gl, string dbgMsg, DebugType type = DebugType.DebugTypeMarker, DebugSeverity severity = DebugSeverity.DebugSeverityNotification, int id = 999999)
{
gl.DebugMessageInsert(DebugSource.DebugSourceApplication, type, id, severity, dbgMsg.Length, dbgMsg);
gl.DebugMessageInsert(DebugSource.DebugSourceApplication, type, (uint)id, severity, (uint)dbgMsg.Length, dbgMsg);
}
}
}

View file

@ -123,13 +123,13 @@ namespace Ryujinx.Graphics.OpenGL.Effects
uint previousProgram = (uint)_gd.Api.GetInteger(GetPName.CurrentProgram);
int previousUnit = _gd.Api.GetInteger(GetPName.ActiveTexture);
_gd.Api.ActiveTexture(TextureUnit.Texture0);
int previousTextureBinding = _gd.Api.GetInteger(GetPName.TextureBinding2D);
uint previousTextureBinding = (uint)_gd.Api.GetInteger(GetPName.TextureBinding2D);
_gd.Api.BindImageTexture(0, textureView.Handle, 0, false, 0, BufferAccessARB.ReadWrite, SizedInternalFormat.Rgba8);
_gd.Api.BindImageTexture(0, textureView.Handle, 0, false, 0, BufferAccessARB.ReadWrite, InternalFormat.Rgba8);
int threadGroupWorkRegionDim = 16;
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
uint dispatchX = (uint)((width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim);
uint dispatchY = (uint)((height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim);
// Scaling pass
float srcWidth = Math.Abs(source.X2 - source.X1);
@ -156,7 +156,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects
// Sharpening Pass
_gd.Api.UseProgram(_sharpeningShaderProgram);
_gd.Api.BindImageTexture(0, destinationTexture.Handle, 0, false, 0, BufferAccessARB.ReadWrite, SizedInternalFormat.Rgba8);
_gd.Api.BindImageTexture(0, destinationTexture.Handle, 0, false, 0, BufferAccessARB.ReadWrite, InternalFormat.Rgba8);
textureView.Bind(0);
_gd.Api.Uniform1(_inputUniform, 0);
_gd.Api.Uniform1(_outputUniform, 0);

View file

@ -31,7 +31,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects
private void Initialize()
{
_shaderProgram = ShaderHelper.CompileProgram(EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/fxaa.glsl"), ShaderType.ComputeShader);
_shaderProgram = ShaderHelper.CompileProgram(_gd.Api, EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/fxaa.glsl"), ShaderType.ComputeShader);
_resolutionUniform = _gd.Api.GetUniformLocation(_shaderProgram, "invResolution");
_inputUniform = _gd.Api.GetUniformLocation(_shaderProgram, "inputTexture");
@ -49,21 +49,21 @@ namespace Ryujinx.Graphics.OpenGL.Effects
var textureView = _textureStorage.CreateView(view.Info, 0, 0) as TextureView;
int previousProgram = _gd.Api.GetInteger(GetPName.CurrentProgram);
uint previousProgram = (uint)_gd.Api.GetInteger(GetPName.CurrentProgram);
int previousUnit = _gd.Api.GetInteger(GetPName.ActiveTexture);
_gd.Api.ActiveTexture(TextureUnit.Texture0);
int previousTextureBinding = _gd.Api.GetInteger(GetPName.TextureBinding2D);
uint previousTextureBinding = (uint)_gd.Api.GetInteger(GetPName.TextureBinding2D);
_gd.Api.BindImageTexture(0, textureView.Handle, 0, false, 0, BufferAccessARB.ReadWrite, SizedInternalFormat.Rgba8);
_gd.Api.BindImageTexture(0, textureView.Handle, 0, false, 0, BufferAccessARB.ReadWrite, InternalFormat.Rgba8);
_gd.Api.UseProgram(_shaderProgram);
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
uint dispatchX = (uint)BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
uint dispatchY = (uint)BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
view.Bind(0);
_gd.Api.Uniform1(_inputUniform, 0);
_gd.Api.Uniform1(_outputUniform, 0);
_gd.Api.Uniform2(_resolutionUniform, (float)view.Width, (float)view.Height);
_gd.Api.Uniform2(_resolutionUniform, view.Width, view.Height);
_gd.Api.DispatchCompute(dispatchX, dispatchY, 1);
_gd.Api.UseProgram(previousProgram);
_gd.Api.MemoryBarrier(MemoryBarrierMask.ShaderImageAccessBarrierBit);

View file

@ -93,13 +93,13 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
var neighbourShaderData = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/smaa_neighbour.glsl");
var shaders = new string[] { presets, edgeShaderData };
var edgeProgram = ShaderHelper.CompileProgram(shaders, ShaderType.ComputeShader);
var edgeProgram = ShaderHelper.CompileProgram(_gd.Api, shaders, ShaderType.ComputeShader);
shaders[1] = blendShaderData;
var blendProgram = ShaderHelper.CompileProgram(shaders, ShaderType.ComputeShader);
var blendProgram = ShaderHelper.CompileProgram(_gd.Api, shaders, ShaderType.ComputeShader);
shaders[1] = neighbourShaderData;
var neighbourProgram = ShaderHelper.CompileProgram(shaders, ShaderType.ComputeShader);
var neighbourProgram = ShaderHelper.CompileProgram(_gd.Api, shaders, ShaderType.ComputeShader);
_edgeShaderPrograms[i] = edgeProgram;
_blendShaderPrograms[i] = blendProgram;
@ -184,14 +184,14 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
var areaTexture = _areaTexture.DefaultView as TextureView;
var searchTexture = _searchTexture.DefaultView as TextureView;
var previousFramebuffer = _gd.Api.GetInteger(GetPName.DrawFramebufferBinding);
uint previousFramebuffer = (uint)_gd.Api.GetInteger(GetPName.DrawFramebufferBinding);
int previousUnit = _gd.Api.GetInteger(GetPName.ActiveTexture);
_gd.Api.ActiveTexture(TextureUnit.Texture0);
int previousTextureBinding0 = _gd.Api.GetInteger(GetPName.TextureBinding2D);
uint previousTextureBinding0 = (uint)_gd.Api.GetInteger(GetPName.TextureBinding2D);
_gd.Api.ActiveTexture(TextureUnit.Texture1);
int previousTextureBinding1 = _gd.Api.GetInteger(GetPName.TextureBinding2D);
uint previousTextureBinding1 = (uint)_gd.Api.GetInteger(GetPName.TextureBinding2D);
_gd.Api.ActiveTexture(TextureUnit.Texture2);
int previousTextureBinding2 = _gd.Api.GetInteger(GetPName.TextureBinding2D);
uint previousTextureBinding2 = (uint)_gd.Api.GetInteger(GetPName.TextureBinding2D);
var framebuffer = new Framebuffer(_gd.Api);
framebuffer.Bind();
@ -206,11 +206,11 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
framebuffer.Dispose();
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
uint dispatchX = (uint)BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
uint dispatchY = (uint)BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
uint previousProgram = (uint)_gd.Api.GetInteger(GetPName.CurrentProgram);
_gd.Api.BindImageTexture(0, edgeOutput.Handle, 0, false, 0, BufferAccessARB.ReadWrite, SizedInternalFormat.Rgba8);
_gd.Api.BindImageTexture(0, edgeOutput.Handle, 0, false, 0, BufferAccessARB.ReadWrite, InternalFormat.Rgba8);
_gd.Api.UseProgram(_edgeShaderPrograms[Quality]);
view.Bind(0);
_gd.Api.Uniform1(_inputUniform, 0);
@ -219,7 +219,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
_gd.Api.DispatchCompute(dispatchX, dispatchY, 1);
_gd.Api.MemoryBarrier(MemoryBarrierMask.ShaderImageAccessBarrierBit);
_gd.Api.BindImageTexture(0, blendOutput.Handle, 0, false, 0, BufferAccessARB.ReadWrite, SizedInternalFormat.Rgba8);
_gd.Api.BindImageTexture(0, blendOutput.Handle, 0, false, 0, BufferAccessARB.ReadWrite,InternalFormat.Rgba8);
_gd.Api.UseProgram(_blendShaderPrograms[Quality]);
edgeOutput.Bind(0);
areaTexture.Bind(1);
@ -232,7 +232,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
_gd.Api.DispatchCompute(dispatchX, dispatchY, 1);
_gd.Api.MemoryBarrier(MemoryBarrierMask.ShaderImageAccessBarrierBit);
_gd.Api.BindImageTexture(0, textureView.Handle, 0, false, 0, BufferAccessARB.ReadWrite, SizedInternalFormat.Rgba8);
_gd.Api.BindImageTexture(0, textureView.Handle, 0, false, 0, BufferAccessARB.ReadWrite, InternalFormat.Rgba8);
_gd.Api.UseProgram(_neighbourShaderPrograms[Quality]);
view.Bind(0);
blendOutput.Bind(1);

View file

@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.OpenGL
drawBuffers[index] = DrawBufferMode.ColorAttachment0 + index;
}
api.DrawBuffers(colorsCount, drawBuffers);
api.DrawBuffers((uint)colorsCount, drawBuffers);
}
private static FramebufferAttachment GetAttachment(Format format)

View file

@ -0,0 +1,161 @@
using Silk.NET.OpenGL.Legacy;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.OpenGL
{
public enum GpuVendor
{
Unknown,
AmdWindows,
AmdUnix,
IntelWindows,
IntelUnix,
Nvidia,
}
readonly struct HardwareCapabilities
{
public readonly bool SupportsAlphaToCoverageDitherControl;
public readonly bool SupportsAstcCompression;
public readonly bool SupportsBlendEquationAdvanced;
public readonly bool SupportsDrawTexture;
public readonly bool SupportsFragmentShaderInterlock;
public readonly bool SupportsFragmentShaderOrdering;
public readonly bool SupportsGeometryShaderPassthrough;
public readonly bool SupportsImageLoadFormatted;
public readonly bool SupportsIndirectParameters;
public readonly bool SupportsParallelShaderCompile;
public readonly bool SupportsPolygonOffsetClamp;
public readonly bool SupportsQuads;
public readonly bool SupportsSeamlessCubemapPerTexture;
public readonly bool SupportsShaderBallot;
public readonly bool SupportsShaderViewportLayerArray;
public readonly bool SupportsViewportArray2;
public readonly bool SupportsTextureCompressionBptc;
public readonly bool SupportsTextureCompressionRgtc;
public readonly bool SupportsTextureCompressionS3tc;
public readonly bool SupportsTextureShadowLod;
public readonly bool SupportsViewportSwizzle;
public bool SupportsMismatchingViewFormat => GpuVendor != GpuVendor.AmdWindows && GpuVendor != GpuVendor.IntelWindows;
public bool SupportsNonConstantTextureOffset => GpuVendor == GpuVendor.Nvidia;
public bool RequiresSyncFlush => GpuVendor == GpuVendor.AmdWindows || IsIntel;
public bool UsePersistentBufferForFlush => GpuVendor == GpuVendor.AmdWindows || GpuVendor == GpuVendor.Nvidia;
public readonly int MaximumComputeSharedMemorySize;
public readonly int StorageBufferOffsetAlignment;
public readonly int TextureBufferOffsetAlignment;
public readonly float MaximumSupportedAnisotropy;
public readonly GpuVendor GpuVendor;
public HardwareCapabilities(
bool supportsAlphaToCoverageDitherControl,
bool supportsAstcCompression,
bool supportsBlendEquationAdvanced,
bool supportsDrawTexture,
bool supportsFragmentShaderInterlock,
bool supportsFragmentShaderOrdering,
bool supportsGeometryShaderPassthrough,
bool supportsImageLoadFormatted,
bool supportsIndirectParameters,
bool supportsParallelShaderCompile,
bool supportsPolygonOffsetClamp,
bool supportsQuads,
bool supportsSeamlessCubemapPerTexture,
bool supportsShaderBallot,
bool supportsShaderViewportLayerArray,
bool supportsViewportArray2,
bool supportsTextureCompressionBptc,
bool supportsTextureCompressionRgtc,
bool supportsTextureCompressionS3Tc,
bool supportsTextureShadowLod,
bool supportsViewportSwizzle,
int maximumComputeSharedMemorySize,
int storageBufferOffsetAlignment,
int textureBufferOffsetAlignment,
float maximumSupportedAnisotropy,
GpuVendor gpuVendor)
{
SupportsAlphaToCoverageDitherControl = supportsAlphaToCoverageDitherControl;
SupportsAstcCompression = supportsAstcCompression;
SupportsBlendEquationAdvanced = supportsBlendEquationAdvanced;
SupportsDrawTexture = supportsDrawTexture;
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
SupportsFragmentShaderOrdering = supportsFragmentShaderOrdering;
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
SupportsImageLoadFormatted = supportsImageLoadFormatted;
SupportsIndirectParameters = supportsIndirectParameters;
SupportsParallelShaderCompile = supportsParallelShaderCompile;
SupportsPolygonOffsetClamp = supportsPolygonOffsetClamp;
SupportsQuads = supportsQuads;
SupportsSeamlessCubemapPerTexture = supportsSeamlessCubemapPerTexture;
SupportsShaderBallot = supportsShaderBallot;
SupportsShaderViewportLayerArray = supportsShaderViewportLayerArray;
SupportsViewportArray2 = supportsViewportArray2;
SupportsTextureCompressionBptc = supportsTextureCompressionBptc;
SupportsTextureCompressionRgtc = supportsTextureCompressionRgtc;
SupportsTextureCompressionS3tc = supportsTextureCompressionS3Tc;
SupportsTextureShadowLod = supportsTextureShadowLod;
SupportsViewportSwizzle = supportsViewportSwizzle;
MaximumComputeSharedMemorySize = maximumComputeSharedMemorySize;
StorageBufferOffsetAlignment = storageBufferOffsetAlignment;
TextureBufferOffsetAlignment = textureBufferOffsetAlignment;
MaximumSupportedAnisotropy = maximumSupportedAnisotropy;
GpuVendor = gpuVendor;
}
public bool IsIntel => GpuVendor == GpuVendor.IntelWindows || GpuVendor == GpuVendor.IntelUnix;
public static unsafe bool HasExtension(GL api, string name)
{
int numExtensions = api.GetInteger(GetPName.NumExtensions);
for (uint extension = 0; extension < numExtensions; extension++)
{
if (Marshal.PtrToStringAnsi((IntPtr)api.GetString(StringName.Extensions, extension)) == name)
{
return true;
}
}
return false;
}
public static unsafe GpuVendor GetGpuVendor(GL api)
{
string vendor = Marshal.PtrToStringAnsi((IntPtr)api.GetString(StringName.Vendor)).ToLowerInvariant();
switch (vendor)
{
case "nvidia corporation":
return GpuVendor.Nvidia;
case "intel":
{
string renderer = Marshal.PtrToStringAnsi((IntPtr)api.GetString(StringName.Renderer)).ToLowerInvariant();
return renderer.Contains("mesa") ? GpuVendor.IntelUnix : GpuVendor.IntelWindows;
}
case "ati technologies inc.":
case "advanced micro devices, inc.":
return GpuVendor.AmdWindows;
case "amd":
case "x.org":
return GpuVendor.AmdUnix;
default:
return GpuVendor.Unknown;
}
}
public static bool SupportsQuadsCheck(GL api)
{
api.GetError(); // Clear any existing error.
api.Begin(PrimitiveType.Quads);
api.End();
return api.GetError() == GLEnum.NoError;
}
}
}

View file

@ -1,143 +0,0 @@
using Silk.NET.OpenGL.Legacy;
using System;
namespace Ryujinx.Graphics.OpenGL
{
static class HwCapabilities
{
private static readonly Lazy<bool> _supportsAlphaToCoverageDitherControl = new(() => HasExtension("GL_NV_alpha_to_coverage_dither_control"));
private static readonly Lazy<bool> _supportsAstcCompression = new(() => HasExtension("GL_KHR_texture_compression_astc_ldr"));
private static readonly Lazy<bool> _supportsBlendEquationAdvanced = new(() => HasExtension("GL_NV_blend_equation_advanced"));
private static readonly Lazy<bool> _supportsDrawTexture = new(() => HasExtension("GL_NV_draw_texture"));
private static readonly Lazy<bool> _supportsFragmentShaderInterlock = new(() => HasExtension("GL_ARB_fragment_shader_interlock"));
private static readonly Lazy<bool> _supportsFragmentShaderOrdering = new(() => HasExtension("GL_INTEL_fragment_shader_ordering"));
private static readonly Lazy<bool> _supportsGeometryShaderPassthrough = new(() => HasExtension("GL_NV_geometry_shader_passthrough"));
private static readonly Lazy<bool> _supportsImageLoadFormatted = new(() => HasExtension("GL_EXT_shader_image_load_formatted"));
private static readonly Lazy<bool> _supportsIndirectParameters = new(() => HasExtension("GL_ARB_indirect_parameters"));
private static readonly Lazy<bool> _supportsParallelShaderCompile = new(() => HasExtension("GL_ARB_parallel_shader_compile"));
private static readonly Lazy<bool> _supportsPolygonOffsetClamp = new(() => HasExtension("GL_EXT_polygon_offset_clamp"));
private static readonly Lazy<bool> _supportsQuads = new(SupportsQuadsCheck);
private static readonly Lazy<bool> _supportsSeamlessCubemapPerTexture = new(() => HasExtension("GL_ARB_seamless_cubemap_per_texture"));
private static readonly Lazy<bool> _supportsShaderBallot = new(() => HasExtension("GL_ARB_shader_ballot"));
private static readonly Lazy<bool> _supportsShaderViewportLayerArray = new(() => HasExtension("GL_ARB_shader_viewport_layer_array"));
private static readonly Lazy<bool> _supportsViewportArray2 = new(() => HasExtension("GL_NV_viewport_array2"));
private static readonly Lazy<bool> _supportsTextureCompressionBptc = new(() => HasExtension("GL_EXT_texture_compression_bptc"));
private static readonly Lazy<bool> _supportsTextureCompressionRgtc = new(() => HasExtension("GL_EXT_texture_compression_rgtc"));
private static readonly Lazy<bool> _supportsTextureCompressionS3tc = new(() => HasExtension("GL_EXT_texture_compression_s3tc"));
private static readonly Lazy<bool> _supportsTextureShadowLod = new(() => HasExtension("GL_EXT_texture_shadow_lod"));
private static readonly Lazy<bool> _supportsViewportSwizzle = new(() => HasExtension("GL_NV_viewport_swizzle"));
private static readonly Lazy<int> _maximumComputeSharedMemorySize = new(() => GetLimit(GLEnum.MaxComputeSharedMemorySize));
private static readonly Lazy<int> _storageBufferOffsetAlignment = new(() => GetLimit(GLEnum.ShaderStorageBufferOffsetAlignment));
private static readonly Lazy<int> _textureBufferOffsetAlignment = new(() => GetLimit(GLEnum.TextureBufferOffsetAlignment));
public enum GpuVendor
{
Unknown,
AmdWindows,
AmdUnix,
IntelWindows,
IntelUnix,
Nvidia,
}
private static readonly Lazy<GpuVendor> _gpuVendor = new(GetGpuVendor);
private static bool IsIntel => _gpuVendor.Value == GpuVendor.IntelWindows || _gpuVendor.Value == GpuVendor.IntelUnix;
public static GpuVendor Vendor => _gpuVendor.Value;
private static readonly Lazy<float> _maxSupportedAnisotropy = new(GL.GetFloat((GetPName)GLEnum.MaxTextureMaxAnisotropy));
public static bool UsePersistentBufferForFlush => _gpuVendor.Value == GpuVendor.AmdWindows || _gpuVendor.Value == GpuVendor.Nvidia;
public static bool SupportsAlphaToCoverageDitherControl => _supportsAlphaToCoverageDitherControl.Value;
public static bool SupportsAstcCompression => _supportsAstcCompression.Value;
public static bool SupportsBlendEquationAdvanced => _supportsBlendEquationAdvanced.Value;
public static bool SupportsDrawTexture => _supportsDrawTexture.Value;
public static bool SupportsFragmentShaderInterlock => _supportsFragmentShaderInterlock.Value;
public static bool SupportsFragmentShaderOrdering => _supportsFragmentShaderOrdering.Value;
public static bool SupportsGeometryShaderPassthrough => _supportsGeometryShaderPassthrough.Value;
public static bool SupportsImageLoadFormatted => _supportsImageLoadFormatted.Value;
public static bool SupportsIndirectParameters => _supportsIndirectParameters.Value;
public static bool SupportsParallelShaderCompile => _supportsParallelShaderCompile.Value;
public static bool SupportsPolygonOffsetClamp => _supportsPolygonOffsetClamp.Value;
public static bool SupportsQuads => _supportsQuads.Value;
public static bool SupportsSeamlessCubemapPerTexture => _supportsSeamlessCubemapPerTexture.Value;
public static bool SupportsShaderBallot => _supportsShaderBallot.Value;
public static bool SupportsShaderViewportLayerArray => _supportsShaderViewportLayerArray.Value;
public static bool SupportsViewportArray2 => _supportsViewportArray2.Value;
public static bool SupportsTextureCompressionBptc => _supportsTextureCompressionBptc.Value;
public static bool SupportsTextureCompressionRgtc => _supportsTextureCompressionRgtc.Value;
public static bool SupportsTextureCompressionS3tc => _supportsTextureCompressionS3tc.Value;
public static bool SupportsTextureShadowLod => _supportsTextureShadowLod.Value;
public static bool SupportsViewportSwizzle => _supportsViewportSwizzle.Value;
public static bool SupportsMismatchingViewFormat => _gpuVendor.Value != GpuVendor.AmdWindows && _gpuVendor.Value != GpuVendor.IntelWindows;
public static bool SupportsNonConstantTextureOffset => _gpuVendor.Value == GpuVendor.Nvidia;
public static bool RequiresSyncFlush => _gpuVendor.Value == GpuVendor.AmdWindows || IsIntel;
public static int MaximumComputeSharedMemorySize => _maximumComputeSharedMemorySize.Value;
public static int StorageBufferOffsetAlignment => _storageBufferOffsetAlignment.Value;
public static int TextureBufferOffsetAlignment => _textureBufferOffsetAlignment.Value;
public static float MaximumSupportedAnisotropy => _maxSupportedAnisotropy.Value;
private static bool HasExtension(string name)
{
int numExtensions = GL.GetInteger(GetPName.NumExtensions);
for (int extension = 0; extension < numExtensions; extension++)
{
if (GL.GetString(StringNameIndexed.Extensions, extension) == name)
{
return true;
}
}
return false;
}
private static int GetLimit(GLEnum name)
{
return GL.GetInteger((GetPName)name);
}
private static GpuVendor GetGpuVendor()
{
string vendor = GL.GetString(StringName.Vendor).ToLowerInvariant();
if (vendor == "nvidia corporation")
{
return GpuVendor.Nvidia;
}
else if (vendor == "intel")
{
string renderer = GL.GetString(StringName.Renderer).ToLowerInvariant();
return renderer.Contains("mesa") ? GpuVendor.IntelUnix : GpuVendor.IntelWindows;
}
else if (vendor == "ati technologies inc." || vendor == "advanced micro devices, inc.")
{
return GpuVendor.AmdWindows;
}
else if (vendor == "amd" || vendor == "x.org")
{
return GpuVendor.AmdUnix;
}
else
{
return GpuVendor.Unknown;
}
}
private static bool SupportsQuadsCheck(GL api)
{
api.GetError(); // Clear any existing error.
api.Begin(PrimitiveType.Quads);
api.End();
return api.GetError() == ErrorCode.NoError;
}
}
}

View file

@ -6,27 +6,27 @@ namespace Ryujinx.Graphics.OpenGL.Image
class Sampler : ISampler
{
public uint Handle { get; private set; }
private readonly GL _api;
private readonly OpenGLRenderer _gd;
public Sampler(GL api, SamplerCreateInfo info)
public Sampler(OpenGLRenderer gd, SamplerCreateInfo info)
{
_api = api;
Handle = _api.GenSampler();
_gd = gd;
Handle = _gd.Api.GenSampler();
_api.SamplerParameter(Handle, SamplerParameterI.MinFilter, (int)info.MinFilter.Convert());
_api.SamplerParameter(Handle, SamplerParameterI.MagFilter, (int)info.MagFilter.Convert());
_gd.Api.SamplerParameter(Handle, SamplerParameterI.MinFilter, (int)info.MinFilter.Convert());
_gd.Api.SamplerParameter(Handle, SamplerParameterI.MagFilter, (int)info.MagFilter.Convert());
if (HwCapabilities.SupportsSeamlessCubemapPerTexture)
if (_gd.Capabilities.SupportsSeamlessCubemapPerTexture)
{
_api.SamplerParameter(Handle, GLEnum.TextureCubeMapSeamless, info.SeamlessCubemap ? 1 : 0);
_gd.Api.SamplerParameter(Handle, GLEnum.TextureCubeMapSeamless, info.SeamlessCubemap ? 1 : 0);
}
_api.SamplerParameter(Handle, SamplerParameterI.WrapS, (int)info.AddressU.Convert());
_api.SamplerParameter(Handle, SamplerParameterI.WrapT, (int)info.AddressV.Convert());
_api.SamplerParameter(Handle, SamplerParameterI.WrapR, (int)info.AddressP.Convert());
_gd.Api.SamplerParameter(Handle, SamplerParameterI.WrapS, (int)info.AddressU.Convert());
_gd.Api.SamplerParameter(Handle, SamplerParameterI.WrapT, (int)info.AddressV.Convert());
_gd.Api.SamplerParameter(Handle, SamplerParameterI.WrapR, (int)info.AddressP.Convert());
_api.SamplerParameter(Handle, SamplerParameterI.CompareMode, (int)info.CompareMode.Convert());
_api.SamplerParameter(Handle, SamplerParameterI.CompareFunc, (int)info.CompareOp.Convert());
_gd.Api.SamplerParameter(Handle, SamplerParameterI.CompareMode, (int)info.CompareMode.Convert());
_gd.Api.SamplerParameter(Handle, SamplerParameterI.CompareFunc, (int)info.CompareOp.Convert());
unsafe
{
@ -38,26 +38,26 @@ namespace Ryujinx.Graphics.OpenGL.Image
info.BorderColor.Alpha,
};
_api.SamplerParameter(Handle, SamplerParameterF.BorderColor, borderColor);
_gd.Api.SamplerParameter(Handle, SamplerParameterF.BorderColor, borderColor);
}
_api.SamplerParameter(Handle, SamplerParameterF.MinLod, info.MinLod);
_api.SamplerParameter(Handle, SamplerParameterF.MaxLod, info.MaxLod);
_api.SamplerParameter(Handle, SamplerParameterF.LodBias, info.MipLodBias);
_gd.Api.SamplerParameter(Handle, SamplerParameterF.MinLod, info.MinLod);
_gd.Api.SamplerParameter(Handle, SamplerParameterF.MaxLod, info.MaxLod);
_gd.Api.SamplerParameter(Handle, SamplerParameterF.LodBias, info.MipLodBias);
_api.SamplerParameter(Handle, SamplerParameterF.MaxAnisotropy, info.MaxAnisotropy);
_gd.Api.SamplerParameter(Handle, SamplerParameterF.MaxAnisotropy, info.MaxAnisotropy);
}
public void Bind(uint unit)
{
_api.BindSampler(unit, Handle);
_gd.Api.BindSampler(unit, Handle);
}
public void Dispose()
{
if (Handle != 0)
{
_api.DeleteSampler(Handle);
_gd.Api.DeleteSampler(Handle);
Handle = 0;
}

View file

@ -238,7 +238,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
int copyWidth = sizeInBlocks ? BitUtils.DivRoundUp(width, blockWidth) : width;
int copyHeight = sizeInBlocks ? BitUtils.DivRoundUp(height, blockHeight) : height;
if (HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows)
if (_gd.Capabilities.GpuVendor == GpuVendor.IntelWindows)
{
_gd.Api.CopyImageSubData(
src.Storage.Handle,

View file

@ -101,15 +101,15 @@ namespace Ryujinx.Graphics.OpenGL.Image
_gd.Api.TexParameter(target, TextureParameterName.DepthStencilTextureMode, (int)Info.DepthStencilMode.Convert());
}
public ITexture CreateView(TextureCreateInfo info, uint firstLayer, uint firstLevel)
public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
{
firstLayer += FirstLayer;
firstLevel += FirstLevel;
firstLayer += (int)FirstLayer;
firstLevel += (int)FirstLevel;
return _parent.CreateView(info, firstLayer, firstLevel);
return _parent.CreateView(info, (uint)firstLayer, (uint)firstLevel);
}
public void CopyTo(ITexture destination, uint firstLayer, uint firstLevel)
public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
{
TextureView destinationView = (TextureView)destination;
@ -118,18 +118,18 @@ namespace Ryujinx.Graphics.OpenGL.Image
if (dstIsMultisample != srcIsMultisample && Info.Format.IsDepthOrStencil())
{
uint layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
uint layers = (uint)Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
CopyWithBlitForDepthMS(destinationView, 0, firstLayer, layers);
}
else if (!dstIsMultisample && srcIsMultisample)
{
uint layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
_gd.TextureCopyMS.CopyMSToNonMS(this, destinationView, 0, firstLayer, layers);
uint layers = (uint)Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
_gd.TextureCopyMS.CopyMSToNonMS(this, destinationView, 0, firstLayer, (int)layers);
}
else if (dstIsMultisample && !srcIsMultisample)
{
uint layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
_gd.TextureCopyMS.CopyNonMSToMS(this, destinationView, 0, firstLayer, layers);
uint layers = (uint)Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
_gd.TextureCopyMS.CopyNonMSToMS(this, destinationView, 0, firstLayer, (int)layers);
}
else if (destinationView.Info.BytesPerPixel != Info.BytesPerPixel)
{
@ -228,7 +228,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
1);
_gd.TextureCopy.Copy(this, intermmediate, srcRegion, dstRegion, false);
_gd.TextureCopy.Copy(intermmediate, destinationView, dstRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1);
_gd.TextureCopy.Copy(intermmediate, destinationView, dstRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, (int)layers, 1);
}
else
{
@ -252,7 +252,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
1);
_gd.TextureCopy.Copy(this, intermmediate, srcRegion, srcRegion, false);
_gd.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1);
_gd.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, (int)layers, 1);
}
}
@ -273,7 +273,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
ReadOnlySpan<byte> data;
if (HwCapabilities.UsePersistentBufferForFlush)
if (_gd.Capabilities.UsePersistentBufferForFlush)
{
data = _gd.PersistentBuffers.Default.GetTextureData(this, size);
}
@ -298,7 +298,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
int size = Info.GetMipSize(level);
if (HwCapabilities.UsePersistentBufferForFlush)
if (_gd.Capabilities.UsePersistentBufferForFlush)
{
return PinnedSpan<byte>.UnsafeFromSpan(_gd.PersistentBuffers.Default.GetTextureData(this, size, layer, level));
}
@ -344,7 +344,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
return WriteTo2D(IntPtr.Zero + offset, layer, level);
}
private int WriteTo2D(IntPtr data, int layer, int level)
private unsafe int WriteTo2D(IntPtr data, int layer, int level)
{
TextureTarget target = Target.Convert();
@ -364,15 +364,37 @@ namespace Ryujinx.Graphics.OpenGL.Image
if (format.IsCompressed)
{
_gd.Api.GetCompressedTextureSubImage(Handle, level, 0, 0, layer, Math.Max(1, Info.Width >> level), Math.Max(1, Info.Height >> level), 1, mipSize, data);
_gd.Api.GetCompressedTextureSubImage(
Handle,
level,
0,
0,
layer,
(uint)Math.Max(1, Info.Width >> level),
(uint)Math.Max(1, Info.Height >> level),
1,
(uint)mipSize,
(void*)data);
}
else if (format.PixelFormat != PixelFormat.DepthStencil)
{
_gd.Api.GetTextureSubImage(Handle, level, 0, 0, layer, Math.Max(1, Info.Width >> level), Math.Max(1, Info.Height >> level), 1, pixelFormat, pixelType, mipSize, data);
_gd.Api.GetTextureSubImage(
Handle,
level,
0,
0,
layer,
(uint)Math.Max(1, Info.Width >> level),
(uint)Math.Max(1, Info.Height >> level),
1,
pixelFormat,
pixelType,
(uint)mipSize,
(void*)data);
}
else
{
_gd.Api.GetTexImage(target, level, pixelFormat, pixelType, data);
_gd.Api.GetTexImage(target, level, pixelFormat, pixelType, (void*)data);
// The GL function returns all layers. Must return the offset of the layer we're interested in.
return target switch
@ -387,7 +409,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
return 0;
}
private void WriteTo(IntPtr data, bool forceBgra = false)
private unsafe void WriteTo(IntPtr data, bool forceBgra = false)
{
TextureTarget target = Target.Convert();
@ -433,11 +455,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
if (format.IsCompressed)
{
_gd.Api.GetCompressedTexImage(target + face, level, data + faceOffset);
_gd.Api.GetCompressedTexImage(target + face, level, (void*)(data + faceOffset));
}
else
{
_gd.Api.GetTexImage(target + face, level, pixelFormat, pixelType, data + faceOffset);
_gd.Api.GetTexImage(target + face, level, pixelFormat, pixelType, (void*)(data + faceOffset));
}
}
@ -697,7 +719,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
uint baseLevel = 0;
// glTexSubImage on cubemap views is broken on Intel, we have to use the storage instead.
if (Target == Target.Cubemap && HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows)
if (Target == Target.Cubemap && _gd.Capabilities.GpuVendor == GpuVendor.IntelWindows)
{
_gd.Api.ActiveTexture(TextureUnit.Texture0);
_gd.Api.BindTexture(target, Storage.Handle);
@ -710,9 +732,9 @@ namespace Ryujinx.Graphics.OpenGL.Image
FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
int width = Info.Width;
int height = Info.Height;
int depth = Info.Depth;
uint width = (uint)Info.Width;
uint height = (uint)Info.Height;
uint depth = (uint)Info.Depth;
int levels = Info.GetLevelsClamped();
int offset = 0;
@ -738,8 +760,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
level,
0,
width,
format.PixelFormat,
mipSize,
(InternalFormat)format.PixelFormat,
(uint)mipSize,
data);
}
else
@ -766,8 +788,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
0,
width,
height,
format.PixelFormat,
mipSize,
(InternalFormat)format.PixelFormat,
(uint)mipSize,
data);
}
else
@ -799,8 +821,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
width,
height,
depth,
format.PixelFormat,
mipSize,
(InternalFormat)format.PixelFormat,
(uint)mipSize,
data);
}
else
@ -829,20 +851,20 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
_gd.Api.CompressedTexSubImage2D(
TextureTarget.TextureCubeMapPositiveX + face,
baseLevel + level,
(int)baseLevel + level,
0,
0,
width,
height,
format.PixelFormat,
mipSize / 6,
(InternalFormat)format.PixelFormat,
(uint)mipSize / 6,
data + faceOffset);
}
else
{
_gd.Api.TexSubImage2D(
TextureTarget.TextureCubeMapPositiveX + face,
baseLevel + level,
(int)baseLevel + level,
0,
0,
width,

View file

@ -1,4 +1,5 @@
using Silk.NET.OpenGL.Legacy;
using Silk.NET.OpenGL.Legacy.Extensions.ARB;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
@ -6,6 +7,7 @@ using Ryujinx.Graphics.OpenGL.Image;
using Ryujinx.Graphics.OpenGL.Queries;
using Ryujinx.Graphics.Shader.Translation;
using System;
using System.Runtime.InteropServices;
using Sampler = Ryujinx.Graphics.OpenGL.Image.Sampler;
namespace Ryujinx.Graphics.OpenGL
@ -39,6 +41,8 @@ namespace Ryujinx.Graphics.OpenGL
internal int BufferCount { get; private set; }
internal HardwareCapabilities Capabilities;
public string GpuVendor { get; private set; }
public string GpuRenderer { get; private set; }
public string GpuVersion { get; private set; }
@ -48,15 +52,15 @@ namespace Ryujinx.Graphics.OpenGL
public OpenGLRenderer(GL api)
{
Api = api;
_pipeline = new Pipeline(Api);
_pipeline = new Pipeline(this);
_counters = new Counters(Api);
_window = new Window(this);
_textureCopy = new TextureCopy(this);
_backgroundTextureCopy = new TextureCopy(this);
TextureCopyIncompatible = new TextureCopyIncompatible(this);
TextureCopyMS = new TextureCopyMS(this);
_sync = new Sync(Api);
PersistentBuffers = new PersistentBuffers();
_sync = new Sync(this);
PersistentBuffers = new PersistentBuffers(Api);
ResourcePool = new ResourcePool();
}
@ -100,12 +104,12 @@ namespace Ryujinx.Graphics.OpenGL
public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info)
{
return new Program(Api, shaders, info.FragmentOutputMap);
return new Program(this, shaders, info.FragmentOutputMap);
}
public ISampler CreateSampler(SamplerCreateInfo info)
{
return new Sampler(Api, info);
return new Sampler(this, info);
}
public ITexture CreateTexture(TextureCreateInfo info)
@ -144,9 +148,9 @@ namespace Ryujinx.Graphics.OpenGL
public Capabilities GetCapabilities()
{
bool intelWindows = HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows;
bool intelUnix = HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelUnix;
bool amdWindows = HwCapabilities.Vendor == HwCapabilities.GpuVendor.AmdWindows;
bool intelWindows = Capabilities.GpuVendor == OpenGL.GpuVendor.IntelWindows;
bool intelUnix = Capabilities.GpuVendor == OpenGL.GpuVendor.IntelUnix;
bool amdWindows = Capabilities.GpuVendor == OpenGL.GpuVendor.AmdWindows;
return new Capabilities(
api: TargetApi.OpenGL,
@ -155,9 +159,9 @@ namespace Ryujinx.Graphics.OpenGL
hasVectorIndexingBug: amdWindows,
needsFragmentOutputSpecialization: false,
reduceShaderPrecision: false,
supportsAstcCompression: HwCapabilities.SupportsAstcCompression,
supportsBc123Compression: HwCapabilities.SupportsTextureCompressionS3tc,
supportsBc45Compression: HwCapabilities.SupportsTextureCompressionRgtc,
supportsAstcCompression: Capabilities.SupportsAstcCompression,
supportsBc123Compression: Capabilities.SupportsTextureCompressionS3tc,
supportsBc45Compression: Capabilities.SupportsTextureCompressionRgtc,
supportsBc67Compression: true, // Should check BPTC extension, but for some reason NVIDIA is not exposing the extension.
supportsEtc2Compression: true,
supports3DTextureCompression: false,
@ -167,39 +171,39 @@ namespace Ryujinx.Graphics.OpenGL
supportsSnormBufferTextureFormat: false,
supports5BitComponentFormat: true,
supportsSparseBuffer: false,
supportsBlendEquationAdvanced: HwCapabilities.SupportsBlendEquationAdvanced,
supportsFragmentShaderInterlock: HwCapabilities.SupportsFragmentShaderInterlock,
supportsFragmentShaderOrderingIntel: HwCapabilities.SupportsFragmentShaderOrdering,
supportsBlendEquationAdvanced: Capabilities.SupportsBlendEquationAdvanced,
supportsFragmentShaderInterlock: Capabilities.SupportsFragmentShaderInterlock,
supportsFragmentShaderOrderingIntel: Capabilities.SupportsFragmentShaderOrdering,
supportsGeometryShader: true,
supportsGeometryShaderPassthrough: HwCapabilities.SupportsGeometryShaderPassthrough,
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
supportsTransformFeedback: true,
supportsImageLoadFormatted: HwCapabilities.SupportsImageLoadFormatted,
supportsLayerVertexTessellation: HwCapabilities.SupportsShaderViewportLayerArray,
supportsMismatchingViewFormat: HwCapabilities.SupportsMismatchingViewFormat,
supportsImageLoadFormatted: Capabilities.SupportsImageLoadFormatted,
supportsLayerVertexTessellation: Capabilities.SupportsShaderViewportLayerArray,
supportsMismatchingViewFormat: Capabilities.SupportsMismatchingViewFormat,
supportsCubemapView: true,
supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
supportsNonConstantTextureOffset: Capabilities.SupportsNonConstantTextureOffset,
supportsScaledVertexFormats: true,
supportsSeparateSampler: false,
supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
supportsShaderBallot: Capabilities.SupportsShaderBallot,
supportsShaderBarrierDivergence: !(intelWindows || intelUnix),
supportsShaderFloat64: true,
supportsTextureGatherOffsets: true,
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
supportsTextureShadowLod: Capabilities.SupportsTextureShadowLod,
supportsVertexStoreAndAtomics: true,
supportsViewportIndexVertexTessellation: HwCapabilities.SupportsShaderViewportLayerArray,
supportsViewportMask: HwCapabilities.SupportsViewportArray2,
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
supportsViewportIndexVertexTessellation: Capabilities.SupportsShaderViewportLayerArray,
supportsViewportMask: Capabilities.SupportsViewportArray2,
supportsViewportSwizzle: Capabilities.SupportsViewportSwizzle,
supportsIndirectParameters: Capabilities.SupportsIndirectParameters,
supportsDepthClipControl: true,
maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?
maximumStorageBuffersPerStage: 16,
maximumTexturesPerStage: 32,
maximumImagesPerStage: 8,
maximumComputeSharedMemorySize: HwCapabilities.MaximumComputeSharedMemorySize,
maximumSupportedAnisotropy: HwCapabilities.MaximumSupportedAnisotropy,
maximumComputeSharedMemorySize: Capabilities.MaximumComputeSharedMemorySize,
maximumSupportedAnisotropy: Capabilities.MaximumSupportedAnisotropy,
shaderSubgroupSize: Constants.MaxSubgroupSize,
storageBufferOffsetAlignment: HwCapabilities.StorageBufferOffsetAlignment,
textureBufferOffsetAlignment: HwCapabilities.TextureBufferOffsetAlignment,
storageBufferOffsetAlignment: Capabilities.StorageBufferOffsetAlignment,
textureBufferOffsetAlignment: Capabilities.TextureBufferOffsetAlignment,
gatherBiasPrecision: intelWindows || amdWindows ? 8 : 0); // Precision is 8 for these vendors on Vulkan.
}
@ -228,11 +232,15 @@ namespace Ryujinx.Graphics.OpenGL
{
Debugger.Initialize(Api, glLogLevel);
LoadFeatures();
PrintGpuInformation();
if (HwCapabilities.SupportsParallelShaderCompile)
if (Capabilities.SupportsParallelShaderCompile)
{
GL.Arb.MaxShaderCompilerThreads(Math.Min(Environment.ProcessorCount, 8));
Api.TryGetExtension(out ArbParallelShaderCompile arbParallelShaderCompile);
arbParallelShaderCompile.MaxShaderCompilerThreads((uint)Math.Min(Environment.ProcessorCount, 8));
}
_counters.Initialize();
@ -240,15 +248,46 @@ namespace Ryujinx.Graphics.OpenGL
// This is required to disable [0, 1] clamping for SNorm outputs on compatibility profiles.
// This call is expected to fail if we're running with a core profile,
// as this clamp target was deprecated, but that's fine as a core profile
// should already have the desired behaviour were outputs are not clamped.
// should already have the desired behaviour when outputs are not clamped.
Api.ClampColor(ClampColorTargetARB.FragmentColorArb, ClampColorModeARB.False);
}
private void PrintGpuInformation()
private void LoadFeatures()
{
GpuVendor = Api.GetString(StringName.Vendor);
GpuRenderer = Api.GetString(StringName.Renderer);
GpuVersion = Api.GetString(StringName.Version);
Capabilities = new HardwareCapabilities(
HardwareCapabilities.HasExtension(Api, "GL_NV_alpha_to_coverage_dither_control"),
HardwareCapabilities.HasExtension(Api, "GL_KHR_texture_compression_astc_ldr"),
HardwareCapabilities.HasExtension(Api, "GL_NV_blend_equation_advanced"),
HardwareCapabilities.HasExtension(Api, "GL_NV_draw_texture"),
HardwareCapabilities.HasExtension(Api, "GL_ARB_fragment_shader_interlock"),
HardwareCapabilities.HasExtension(Api, "GL_INTEL_fragment_shader_ordering"),
HardwareCapabilities.HasExtension(Api, "GL_NV_geometry_shader_passthrough"),
HardwareCapabilities.HasExtension(Api, "GL_EXT_shader_image_load_formatted"),
HardwareCapabilities.HasExtension(Api, "GL_ARB_indirect_parameters"),
HardwareCapabilities.HasExtension(Api, "GL_ARB_parallel_shader_compile"),
HardwareCapabilities.HasExtension(Api, "GL_EXT_polygon_offset_clamp"),
HardwareCapabilities.SupportsQuadsCheck(Api),
HardwareCapabilities.HasExtension(Api, "GL_ARB_seamless_cubemap_per_texture"),
HardwareCapabilities.HasExtension(Api, "GL_ARB_shader_ballot"),
HardwareCapabilities.HasExtension(Api, "GL_ARB_shader_viewport_layer_array"),
HardwareCapabilities.HasExtension(Api, "GL_NV_viewport_array2"),
HardwareCapabilities.HasExtension(Api, "GL_EXT_texture_compression_bptc"),
HardwareCapabilities.HasExtension(Api, "GL_EXT_texture_compression_rgtc"),
HardwareCapabilities.HasExtension(Api, "GL_EXT_texture_compression_s3tc"),
HardwareCapabilities.HasExtension(Api, "GL_EXT_texture_shadow_lod"),
HardwareCapabilities.HasExtension(Api, "GL_NV_viewport_swizzle"),
Api.GetInteger(GLEnum.MaxComputeSharedMemorySize),
Api.GetInteger(GLEnum.ShaderStorageBufferOffsetAlignment),
Api.GetInteger(GLEnum.TextureBufferOffsetAlignment),
Api.GetFloat(GLEnum.MaxTextureMaxAnisotropy),
HardwareCapabilities.GetGpuVendor(Api));
}
private unsafe void PrintGpuInformation()
{
GpuVendor = Marshal.PtrToStringAnsi((IntPtr)Api.GetString(StringName.Vendor));
GpuRenderer = Marshal.PtrToStringAnsi((IntPtr)Api.GetString(StringName.Renderer));
GpuVersion = Marshal.PtrToStringAnsi((IntPtr)Api.GetString(StringName.Version));
Logger.Notice.Print(LogClass.Gpu, $"{GpuVendor} {GpuRenderer} ({GpuVersion})");
}
@ -292,7 +331,7 @@ namespace Ryujinx.Graphics.OpenGL
public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
{
return new Program(Api, programBinary, hasFragmentShader, info.FragmentOutputMap);
return new Program(this, programBinary, hasFragmentShader, info.FragmentOutputMap);
}
public void CreateSync(ulong id, bool strict)

View file

@ -11,33 +11,41 @@ namespace Ryujinx.Graphics.OpenGL
{
class PersistentBuffers : IDisposable
{
private readonly PersistentBuffer _main = new();
private readonly PersistentBuffer _background = new();
private readonly GL _api;
private readonly PersistentBuffer _main;
private readonly PersistentBuffer _background;
private readonly Dictionary<BufferHandle, IntPtr> _maps = new();
public PersistentBuffer Default => BackgroundContextWorker.InBackground ? _background : _main;
public PersistentBuffers(GL api)
{
_api = api;
_main = new(_api);
_background = new(_api);
}
public void Dispose()
{
_main?.Dispose();
_background?.Dispose();
}
public void Map(BufferHandle handle, int size)
public unsafe void Map(BufferHandle handle, int size)
{
GL.BindBuffer(BufferTargetARB.CopyWriteBuffer, handle.ToInt32());
IntPtr ptr = GL.MapBufferRange(BufferTargetARB.CopyWriteBuffer, IntPtr.Zero, size, BufferAccessMask.MapReadBit | BufferAccessMask.MapPersistentBit);
_api.BindBuffer(BufferTargetARB.CopyWriteBuffer, handle.ToUInt32());
void* ptr = _api.MapBufferRange(BufferTargetARB.CopyWriteBuffer, IntPtr.Zero, (uint)size, MapBufferAccessMask.ReadBit | MapBufferAccessMask.PersistentBit);
_maps[handle] = ptr;
_maps[handle] = (IntPtr)ptr;
}
public void Unmap(BufferHandle handle)
{
if (_maps.ContainsKey(handle))
{
GL.BindBuffer(BufferTargetARB.CopyWriteBuffer, handle.ToInt32());
GL.UnmapBuffer(BufferTargetARB.CopyWriteBuffer);
_api.BindBuffer(BufferTargetARB.CopyWriteBuffer, handle.ToUInt32());
_api.UnmapBuffer(BufferTargetARB.CopyWriteBuffer);
_maps.Remove(handle);
}
@ -51,6 +59,7 @@ namespace Ryujinx.Graphics.OpenGL
class PersistentBuffer : IDisposable
{
private readonly GL _api;
private IntPtr _bufferMap;
private uint _copyBufferHandle;
private int _copyBufferSize;
@ -58,24 +67,29 @@ namespace Ryujinx.Graphics.OpenGL
private byte[] _data;
private IntPtr _dataMap;
private void EnsureBuffer(int requiredSize)
public PersistentBuffer(GL api)
{
_api = api;
}
private unsafe void EnsureBuffer(int requiredSize)
{
if (_copyBufferSize < requiredSize && _copyBufferHandle != 0)
{
GL.DeleteBuffer(_copyBufferHandle);
_api.DeleteBuffer(_copyBufferHandle);
_copyBufferHandle = 0;
}
if (_copyBufferHandle == 0)
{
_copyBufferHandle = GL.GenBuffer();
_copyBufferHandle = _api.GenBuffer();
_copyBufferSize = requiredSize;
GL.BindBuffer(BufferTargetARB.CopyWriteBuffer, _copyBufferHandle);
GL.BufferStorage(BufferTargetARB.CopyWriteBuffer, requiredSize, IntPtr.Zero, BufferStorageFlags.MapReadBit | BufferStorageFlags.MapPersistentBit);
_api.BindBuffer(BufferTargetARB.CopyWriteBuffer, _copyBufferHandle);
_api.BufferStorage(BufferStorageTarget.CopyWriteBuffer, (uint)requiredSize, IntPtr.Zero, BufferStorageMask.MapReadBit | BufferStorageMask.MapPersistentBit);
_bufferMap = GL.MapBufferRange(BufferTargetARB.CopyWriteBuffer, IntPtr.Zero, requiredSize, BufferAccessMask.MapReadBit | BufferAccessMask.MapPersistentBit);
_bufferMap = (IntPtr)_api.MapBufferRange(BufferTargetARB.CopyWriteBuffer, IntPtr.Zero, (uint)requiredSize, MapBufferAccessMask.ReadBit | MapBufferAccessMask.PersistentBit);
}
}
@ -91,30 +105,30 @@ namespace Ryujinx.Graphics.OpenGL
return _dataMap;
}
private static void Sync()
private void Sync()
{
GL.MemoryBarrier(MemoryBarrierFlags.ClientMappedBufferBarrierBit);
_api.MemoryBarrier(MemoryBarrierMask.ClientMappedBufferBarrierBit);
IntPtr sync = GL.FenceSync(SyncCondition.SyncGpuCommandsComplete, WaitSyncFlags.None);
WaitSyncStatus syncResult = GL.ClientWaitSync(sync, ClientWaitSyncFlags.SyncFlushCommandsBit, 1000000000);
IntPtr sync = _api.FenceSync(SyncCondition.SyncGpuCommandsComplete, SyncBehaviorFlags.None);
GLEnum syncResult = _api.ClientWaitSync(sync, SyncObjectMask.Bit, 1000000000);
if (syncResult == WaitSyncStatus.TimeoutExpired)
if (syncResult == GLEnum.TimeoutExpired)
{
Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to sync persistent buffer state within 1000ms. Continuing...");
}
GL.DeleteSync(sync);
_api.DeleteSync(sync);
}
public unsafe ReadOnlySpan<byte> GetTextureData(TextureView view, int size)
{
EnsureBuffer(size);
GL.BindBuffer(BufferTargetARB.PixelPackBuffer, _copyBufferHandle);
_api.BindBuffer(BufferTargetARB.PixelPackBuffer, _copyBufferHandle);
view.WriteToPbo(0, false);
GL.BindBuffer(BufferTargetARB.PixelPackBuffer, 0);
_api.BindBuffer(BufferTargetARB.PixelPackBuffer, 0);
Sync();
@ -125,11 +139,11 @@ namespace Ryujinx.Graphics.OpenGL
{
EnsureBuffer(size);
GL.BindBuffer(BufferTargetARB.PixelPackBuffer, _copyBufferHandle);
_api.BindBuffer(BufferTargetARB.PixelPackBuffer, _copyBufferHandle);
int offset = view.WriteToPbo2D(0, layer, level);
GL.BindBuffer(BufferTargetARB.PixelPackBuffer, 0);
_api.BindBuffer(BufferTargetARB.PixelPackBuffer, 0);
Sync();
@ -140,12 +154,12 @@ namespace Ryujinx.Graphics.OpenGL
{
EnsureBuffer(size);
GL.BindBuffer(BufferTargetARB.CopyReadBuffer, buffer.ToUInt32());
GL.BindBuffer(BufferTargetARB.CopyWriteBuffer, _copyBufferHandle);
_api.BindBuffer(BufferTargetARB.CopyReadBuffer, buffer.ToUInt32());
_api.BindBuffer(BufferTargetARB.CopyWriteBuffer, _copyBufferHandle);
GL.CopyBufferSubData(BufferTargetARB.CopyReadBuffer, BufferTargetARB.CopyWriteBuffer, (IntPtr)offset, IntPtr.Zero, size);
_api.CopyBufferSubData(CopyBufferSubDataTarget.CopyReadBuffer, CopyBufferSubDataTarget.CopyWriteBuffer, offset, IntPtr.Zero, (uint)size);
GL.BindBuffer(BufferTargetARB.CopyWriteBuffer, 0);
_api.BindBuffer(BufferTargetARB.CopyWriteBuffer, 0);
Sync();
@ -156,7 +170,7 @@ namespace Ryujinx.Graphics.OpenGL
{
if (_copyBufferHandle != 0)
{
GL.DeleteBuffer(_copyBufferHandle);
_api.DeleteBuffer(_copyBufferHandle);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
using Silk.NET.OpenGL.Legacy;
using Silk.NET.OpenGL.Legacy.Extensions.ARB;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
@ -27,18 +28,18 @@ namespace Ryujinx.Graphics.OpenGL
}
}
private readonly GL _api;
private readonly OpenGLRenderer _gd;
private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete;
private uint[] _shaderHandles;
public int FragmentOutputMap { get; }
public Program(GL api, ShaderSource[] shaders, int fragmentOutputMap)
public unsafe Program(OpenGLRenderer gd, ShaderSource[] shaders, int fragmentOutputMap)
{
_api = api;
Handle = _api.CreateProgram();
_gd = gd;
Handle = _gd.Api.CreateProgram();
_api.ProgramParameter(Handle, ProgramParameterPName.BinaryRetrievableHint, 1);
_gd.Api.ProgramParameter(Handle, ProgramParameterPName.BinaryRetrievableHint, 1);
_shaderHandles = new uint[shaders.Length];
bool hasFragmentShader = false;
@ -52,34 +53,37 @@ namespace Ryujinx.Graphics.OpenGL
hasFragmentShader = true;
}
uint shaderHandle = _api.CreateShader(shader.Stage.Convert());
uint shaderHandle = _gd.Api.CreateShader(shader.Stage.Convert());
switch (shader.Language)
{
case TargetLanguage.Glsl:
_api.ShaderSource(shaderHandle, shader.Code);
_api.CompileShader(shaderHandle);
_gd.Api.ShaderSource(shaderHandle, shader.Code);
_gd.Api.CompileShader(shaderHandle);
break;
case TargetLanguage.Spirv:
_api.ShaderBinary(1, ref shaderHandle, ShaderBinaryFormat.ShaderBinaryFormatSpirV, shader.BinaryCode, shader.BinaryCode.Length);
_api.SpecializeShader(shaderHandle, "main", 0, (int[])null, (int[])null);
fixed (byte* ptr = shader.BinaryCode.AsSpan())
{
_gd.Api.ShaderBinary(1, in shaderHandle, ShaderBinaryFormat.ShaderBinaryFormatSpirV, ptr, (uint)shader.BinaryCode.Length);
}
_gd.Api.SpecializeShader(shaderHandle, "main", 0, (uint[])null, (uint[])null);
break;
}
_api.AttachShader(Handle, shaderHandle);
_gd.Api.AttachShader(Handle, shaderHandle);
_shaderHandles[index] = shaderHandle;
}
_api.LinkProgram(Handle);
_gd.Api.LinkProgram(Handle);
FragmentOutputMap = hasFragmentShader ? fragmentOutputMap : 0;
}
public Program(GL api, ReadOnlySpan<byte> code, bool hasFragmentShader, int fragmentOutputMap)
public Program(OpenGLRenderer gd, ReadOnlySpan<byte> code, bool hasFragmentShader, int fragmentOutputMap)
{
_api = api;
Handle = _api.CreateProgram();
_gd = gd;
Handle = _gd.Api.CreateProgram();
if (code.Length >= 4)
{
@ -89,7 +93,7 @@ namespace Ryujinx.Graphics.OpenGL
{
fixed (byte* ptr = code)
{
_api.ProgramBinary(Handle, binaryFormat, (IntPtr)ptr, code.Length - 4);
_gd.Api.ProgramBinary(Handle, (GLEnum)binaryFormat, (IntPtr)ptr, (uint)code.Length - 4);
}
}
}
@ -99,14 +103,14 @@ namespace Ryujinx.Graphics.OpenGL
public void Bind()
{
_api.UseProgram(Handle);
_gd.Api.UseProgram(Handle);
}
public ProgramLinkStatus CheckProgramLink(bool blocking)
{
if (!blocking && HwCapabilities.SupportsParallelShaderCompile)
if (!blocking && _gd.Capabilities.SupportsParallelShaderCompile)
{
_api.GetProgram(Handle, (GetProgramParameterName)ArbParallelShaderCompile.CompletionStatusArb, out int completed);
_gd.Api.GetProgram(Handle, (GLEnum)ARB.CompletionStatusArb, out int completed);
if (completed == 0)
{
@ -114,14 +118,14 @@ namespace Ryujinx.Graphics.OpenGL
}
}
_api.GetProgram(Handle, ProgramPropertyARB.LinkStatus, out int status);
_gd.Api.GetProgram(Handle, ProgramPropertyARB.LinkStatus, out int status);
DeleteShaders();
if (status == 0)
{
_status = ProgramLinkStatus.Failure;
string log = _api.GetProgramInfoLog(Handle);
string log = _gd.Api.GetProgramInfoLog(Handle);
if (log.Length > MaxShaderLogLength)
{
@ -138,15 +142,19 @@ namespace Ryujinx.Graphics.OpenGL
return _status;
}
public byte[] GetBinary()
public unsafe byte[] GetBinary()
{
_api.GetProgram(Handle, ProgramPropertyARB.ProgramBinaryLength, out int size);
_gd.Api.GetProgram(Handle, ProgramPropertyARB.ProgramBinaryLength, out int size);
byte[] data = new byte[size + 4];
byte[] data = new byte[size];
GLEnum binFormat;
_api.GetProgramBinary(Handle, size, out _, out ShaderBinaryFormat binFormat, data);
fixed (byte* ptr = data)
{
_gd.Api.GetProgramBinary(Handle, (uint)size, out _, out binFormat, ptr);
}
BinaryPrimitives.WriteInt32LittleEndian(data.AsSpan(size, 4), (int)binFormat);
BinaryPrimitives.WriteInt32LittleEndian(data, (int)binFormat);
return data;
}
@ -157,8 +165,8 @@ namespace Ryujinx.Graphics.OpenGL
{
foreach (uint shaderHandle in _shaderHandles)
{
_api.DetachShader(Handle, shaderHandle);
_api.DeleteShader(shaderHandle);
_gd.Api.DetachShader(Handle, shaderHandle);
_gd.Api.DeleteShader(shaderHandle);
}
_shaderHandles = null;
@ -170,7 +178,7 @@ namespace Ryujinx.Graphics.OpenGL
if (Handle != 0)
{
DeleteShaders();
_api.DeleteProgram(Handle);
_gd.Api.DeleteProgram(Handle);
Handle = 0;
}

View file

@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
unsafe
{
_bufferMap = new IntPtr(_api.MapBufferRange(BufferTargetARB.QueryBuffer, IntPtr.Zero, sizeof(long), MapBufferAccessMask.ReadBit | MapBufferAccessMask.WriteBit | MapBufferAccessMask.PersistentBit));
_bufferMap = (IntPtr)_api.MapBufferRange(BufferTargetARB.QueryBuffer, IntPtr.Zero, sizeof(long), MapBufferAccessMask.ReadBit | MapBufferAccessMask.WriteBit | MapBufferAccessMask.PersistentBit);
}
}

View file

@ -7,6 +7,7 @@
<ItemGroup>
<PackageReference Include="Silk.NET.OpenGL.Legacy" />
<PackageReference Include="Silk.NET.OpenGL.Legacy.Extensions.ARB" />
<PackageReference Include="Silk.NET.OpenGL.Legacy.Extensions.EXT" />
<PackageReference Include="Silk.NET.OpenGL.Legacy.Extensions.NV" />
</ItemGroup>

View file

@ -14,15 +14,15 @@ namespace Ryujinx.Graphics.OpenGL
public IntPtr Handle;
}
private ulong _firstHandle = 0;
private static SyncBehaviorFlags SyncFlags => HwCapabilities.RequiresSyncFlush ? SyncBehaviorFlags.None : SyncBehaviorFlags.SyncFlushCommandsBit;
private ulong _firstHandle;
private SyncObjectMask SyncFlags => _gd.Capabilities.RequiresSyncFlush ? 0 : SyncObjectMask.Bit;
private readonly List<SyncHandle> _handles = new();
private readonly GL _api;
private readonly OpenGLRenderer _gd;
public Sync(GL api)
public Sync(OpenGLRenderer gd)
{
_api = api;
_gd = gd;
}
public void Create(ulong id)
@ -30,14 +30,14 @@ namespace Ryujinx.Graphics.OpenGL
SyncHandle handle = new()
{
ID = id,
Handle = _api.FenceSync(SyncCondition.SyncGpuCommandsComplete, SyncBehaviorFlags.None),
Handle = _gd.Api.FenceSync(SyncCondition.SyncGpuCommandsComplete, SyncBehaviorFlags.None),
};
if (HwCapabilities.RequiresSyncFlush)
if (_gd.Capabilities.RequiresSyncFlush)
{
// Force commands to flush up to the syncpoint.
_api.ClientWaitSync(handle.Handle, SyncBehaviorFlags.SyncFlushCommandsBit, 0);
_gd.Api.ClientWaitSync(handle.Handle, SyncObjectMask.Bit, 0);
}
lock (_handles)
@ -63,7 +63,7 @@ namespace Ryujinx.Graphics.OpenGL
if (handle.ID > lastHandle)
{
GLEnum syncResult = _api.ClientWaitSync(handle.Handle, SyncFlags, 0);
GLEnum syncResult = _gd.Api.ClientWaitSync(handle.Handle, SyncFlags, 0);
if (syncResult == GLEnum.AlreadySignaled)
{
@ -107,7 +107,7 @@ namespace Ryujinx.Graphics.OpenGL
return;
}
GLEnum syncResult = _api.ClientWaitSync(result.Handle, SyncFlags, 1000000000);
GLEnum syncResult = _gd.Api.ClientWaitSync(result.Handle, SyncFlags, 1000000000);
if (syncResult == GLEnum.TimeoutExpired)
{
@ -134,7 +134,7 @@ namespace Ryujinx.Graphics.OpenGL
break;
}
GLEnum syncResult = _api.ClientWaitSync(first.Handle, SyncFlags, 0);
GLEnum syncResult = _gd.Api.ClientWaitSync(first.Handle, SyncFlags, 0);
if (syncResult == GLEnum.AlreadySignaled)
{
@ -145,7 +145,7 @@ namespace Ryujinx.Graphics.OpenGL
{
_firstHandle = first.ID + 1;
_handles.RemoveAt(0);
_api.DeleteSync(first.Handle);
_gd.Api.DeleteSync(first.Handle);
first.Handle = IntPtr.Zero;
}
}
@ -166,7 +166,7 @@ namespace Ryujinx.Graphics.OpenGL
{
lock (handle)
{
_api.DeleteSync(handle.Handle);
_gd.Api.DeleteSync(handle.Handle);
handle.Handle = IntPtr.Zero;
}
}

View file

@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.OpenGL
{
class VertexArray : IDisposable
{
public int Handle { get; private set; }
public uint Handle { get; private set; }
private readonly VertexAttribDescriptor[] _vertexAttribs;
private readonly VertexBufferDescriptor[] _vertexBuffers;
@ -23,20 +23,22 @@ namespace Ryujinx.Graphics.OpenGL
private readonly BufferHandle _tempIndexBuffer;
private BufferHandle _tempVertexBuffer;
private int _tempVertexBufferSize;
private readonly GL _api;
public VertexArray()
public VertexArray(GL api)
{
Handle = GL.GenVertexArray();
_api = api;
Handle = _api.GenVertexArray();
_vertexAttribs = new VertexAttribDescriptor[Constants.MaxVertexAttribs];
_vertexBuffers = new VertexBufferDescriptor[Constants.MaxVertexBuffers];
_tempIndexBuffer = Buffer.Create();
_tempIndexBuffer = Buffer.Create(_api);
}
public void Bind()
{
GL.BindVertexArray(Handle);
_api.BindVertexArray(Handle);
}
public void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers)
@ -56,15 +58,15 @@ namespace Ryujinx.Graphics.OpenGL
minVertexCount = vertexCount;
}
GL.BindVertexBuffer(bindingIndex, vb.Buffer.Handle.ToInt32(), (IntPtr)vb.Buffer.Offset, vb.Stride);
GL.VertexBindingDivisor(bindingIndex, vb.Divisor);
_api.BindVertexBuffer((uint)bindingIndex, vb.Buffer.Handle.ToUInt32(), vb.Buffer.Offset, (uint)vb.Stride);
_api.VertexBindingDivisor((uint)bindingIndex, (uint)vb.Divisor);
_vertexBuffersInUse |= 1u << bindingIndex;
}
else
{
if ((_vertexBuffersInUse & (1u << bindingIndex)) != 0)
{
GL.BindVertexBuffer(bindingIndex, 0, IntPtr.Zero, 0);
_api.BindVertexBuffer((uint)bindingIndex, 0, IntPtr.Zero, 0);
_vertexBuffersInUse &= ~(1u << bindingIndex);
}
}
@ -111,16 +113,16 @@ namespace Ryujinx.Graphics.OpenGL
{
VertexAttribType type = (VertexAttribType)fmtInfo.PixelType;
GL.VertexAttribFormat(index, size, type, fmtInfo.Normalized, offset);
_api.VertexAttribFormat((uint)index, size, type, fmtInfo.Normalized, (uint)offset);
}
else
{
VertexAttribIntegerType type = (VertexAttribIntegerType)fmtInfo.PixelType;
VertexAttribIType type = (VertexAttribIType)fmtInfo.PixelType;
GL.VertexAttribIFormat(index, size, type, offset);
_api.VertexAttribIFormat((uint)index, size, type, (uint)offset);
}
GL.VertexAttribBinding(index, attrib.BufferIndex);
_api.VertexAttribBinding((uint)index, (uint)attrib.BufferIndex);
_vertexAttribs[index] = attrib;
}
@ -134,19 +136,19 @@ namespace Ryujinx.Graphics.OpenGL
public void SetIndexBuffer(BufferRange range)
{
_indexBuffer = range;
GL.BindBuffer(BufferTargetARB.ElementArrayBuffer, range.Handle.ToInt32());
_api.BindBuffer(BufferTargetARB.ElementArrayBuffer, range.Handle.ToUInt32());
}
public void SetRangeOfIndexBuffer()
{
Buffer.Resize(_tempIndexBuffer, _indexBuffer.Size);
Buffer.Copy(_indexBuffer.Handle, _tempIndexBuffer, _indexBuffer.Offset, 0, _indexBuffer.Size);
GL.BindBuffer(BufferTargetARB.ElementArrayBuffer, _tempIndexBuffer.ToInt32());
Buffer.Resize(_api, _tempIndexBuffer, _indexBuffer.Size);
Buffer.Copy(_api, _indexBuffer.Handle, _tempIndexBuffer, _indexBuffer.Offset, 0, _indexBuffer.Size);
_api.BindBuffer(BufferTargetARB.ElementArrayBuffer, _tempIndexBuffer.ToUInt32());
}
public void RestoreIndexBuffer()
{
GL.BindBuffer(BufferTargetARB.ElementArrayBuffer, _indexBuffer.Handle.ToInt32());
_api.BindBuffer(BufferTargetARB.ElementArrayBuffer, _indexBuffer.Handle.ToUInt32());
}
public void PreDraw(int vertexCount)
@ -185,10 +187,10 @@ namespace Ryujinx.Graphics.OpenGL
{
BufferHandle tempVertexBuffer = EnsureTempVertexBufferSize(currentTempVbOffset + requiredSize);
Buffer.Copy(vb.Buffer.Handle, tempVertexBuffer, vb.Buffer.Offset, currentTempVbOffset, vb.Buffer.Size);
Buffer.Clear(tempVertexBuffer, currentTempVbOffset + vb.Buffer.Size, requiredSize - vb.Buffer.Size, 0);
Buffer.Copy(_api, vb.Buffer.Handle, tempVertexBuffer, vb.Buffer.Offset, currentTempVbOffset, vb.Buffer.Size);
Buffer.Clear(_api, tempVertexBuffer, currentTempVbOffset + vb.Buffer.Size, (uint)(requiredSize - vb.Buffer.Size), 0);
GL.BindVertexBuffer(vbIndex, tempVertexBuffer.ToInt32(), (IntPtr)currentTempVbOffset, vb.Stride);
_api.BindVertexBuffer((uint)vbIndex, tempVertexBuffer.ToUInt32(), (IntPtr)currentTempVbOffset, (uint)vb.Stride);
currentTempVbOffset += requiredSize;
_vertexBuffersLimited |= 1u << vbIndex;
@ -208,12 +210,12 @@ namespace Ryujinx.Graphics.OpenGL
if (tempVertexBuffer == BufferHandle.Null)
{
tempVertexBuffer = Buffer.Create(size);
tempVertexBuffer = Buffer.Create(_api, size);
_tempVertexBuffer = tempVertexBuffer;
return tempVertexBuffer;
}
Buffer.Resize(_tempVertexBuffer, size);
Buffer.Resize(_api, _tempVertexBuffer, size);
}
return tempVertexBuffer;
@ -234,7 +236,7 @@ namespace Ryujinx.Graphics.OpenGL
ref var vb = ref _vertexBuffers[vbIndex];
GL.BindVertexBuffer(vbIndex, vb.Buffer.Handle.ToInt32(), (IntPtr)vb.Buffer.Offset, vb.Stride);
_api.BindVertexBuffer((uint)vbIndex, vb.Buffer.Handle.ToUInt32(), (IntPtr)vb.Buffer.Offset, (uint)vb.Stride);
buffersLimited &= ~(1u << vbIndex);
}
@ -250,7 +252,7 @@ namespace Ryujinx.Graphics.OpenGL
if ((_vertexAttribsInUse & mask) == 0)
{
_vertexAttribsInUse |= mask;
GL.EnableVertexAttribArray(index);
_api.EnableVertexAttribArray((uint)index);
}
}
@ -262,8 +264,8 @@ namespace Ryujinx.Graphics.OpenGL
if ((_vertexAttribsInUse & mask) != 0)
{
_vertexAttribsInUse &= ~mask;
GL.DisableVertexAttribArray(index);
GL.VertexAttrib4(index, 0f, 0f, 0f, 1f);
_api.DisableVertexAttribArray((uint)index);
_api.VertexAttrib4((uint)index, 0f, 0f, 0f, 1f);
}
}
@ -271,7 +273,7 @@ namespace Ryujinx.Graphics.OpenGL
{
if (Handle != 0)
{
GL.DeleteVertexArray(Handle);
_api.DeleteVertexArray(Handle);
Handle = 0;
}

View file

@ -252,12 +252,13 @@ namespace Ryujinx.Graphics.OpenGL
_initialized = true;
}
public void CaptureFrame(int x, int y, uint width, uint height, bool isBgra, bool flipX, bool flipY)
public unsafe void CaptureFrame(int x, int y, uint width, uint height, bool isBgra, bool flipX, bool flipY)
{
long size = 4 * width * height;
byte[] bitmap = new byte[size];
_gd.Api.ReadPixels(x, y, width, height, isBgra ? PixelFormat.Bgra : PixelFormat.Rgba, PixelType.UnsignedByte, bitmap);
_gd.Api.ReadPixels(x, y, width, height, isBgra ? PixelFormat.Bgra : PixelFormat.Rgba, PixelType.UnsignedByte, out int data);
var bitmap = new Span<byte>((void*)data, (int)size).ToArray();
_gd.OnScreenCaptured(new ScreenCaptureImageInfo((int)width, (int)height, isBgra, bitmap, flipX, flipY));
}

View file

@ -1,4 +1,4 @@
using OpenTK;
// using OpenTK;
using Silk.NET.OpenGL.Legacy;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;

View file

@ -532,7 +532,8 @@ namespace Ryujinx.Headless.SDL2
preferredGpuId);
}
return new OpenGLRenderer();
var openGlWindow = (OpenGLWindow)window;
return new OpenGLRenderer(window.);
}
private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options)

View file

@ -823,7 +823,7 @@ namespace Ryujinx.Ava
}
else
{
renderer = new OpenGLRenderer();
renderer = new OpenGLRenderer((RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL).CreateApi());
}
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;

View file

@ -1,4 +1,4 @@
using OpenTK.Graphics.OpenGL;
using Silk.NET.OpenGL.Legacy;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
@ -44,6 +44,13 @@ namespace Ryujinx.Ava.UI.Renderer
throw new PlatformNotSupportedException();
}
Context.Initialize(_window);
Context.MakeCurrent(_window);
Context.MakeCurrent(null);
}
public GL CreateApi()
{
var flags = OpenGLContextFlags.Compat;
if (ConfigurationState.Instance.Logger.GraphicsDebugLevel != GraphicsDebugLevel.None)
{
@ -54,12 +61,7 @@ namespace Ryujinx.Ava.UI.Renderer
Context = PlatformHelper.CreateOpenGLContext(graphicsMode, 3, 3, flags);
Context.Initialize(_window);
Context.MakeCurrent(_window);
GL.LoadBindings(new OpenTKBindingsContext(Context.GetProcAddress));
Context.MakeCurrent(null);
return GL.GetApi(Context.GetProcAddress);
}
public void MakeCurrent(bool unbind = false, bool shouldThrow = true)

View file

@ -1,4 +1,4 @@
using OpenTK.Graphics.OpenGL;
using Silk.NET.OpenGL.Legacy;
using Ryujinx.Graphics.OpenGL;
using SPB.Graphics;
using SPB.Graphics.OpenGL;
@ -9,11 +9,13 @@ namespace Ryujinx.Ava.UI.Renderer
{
class SPBOpenGLContext : IOpenGLContext
{
private readonly GL _api;
private readonly OpenGLContextBase _context;
private readonly NativeWindowBase _window;
private SPBOpenGLContext(OpenGLContextBase context, NativeWindowBase window)
private SPBOpenGLContext(GL api, OpenGLContextBase context, NativeWindowBase window)
{
_api = api;
_context = context;
_window = window;
}
@ -39,11 +41,11 @@ namespace Ryujinx.Ava.UI.Renderer
context.Initialize(window);
context.MakeCurrent(window);
GL.LoadBindings(new OpenTKBindingsContext(context.GetProcAddress));
GL api = GL.GetApi(context.GetProcAddress);
context.MakeCurrent(null);
return new SPBOpenGLContext(context, window);
return new SPBOpenGLContext(api, context, window);
}
}
}