| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- using OpenTK.Graphics.OpenGL;
- using Ryujinx.Graphics.GAL;
- using System;
- using System.Numerics;
- namespace Ryujinx.Graphics.OpenGL.Image
- {
- class TextureCopyMS
- {
- private const string ComputeShaderMSToNonMS = @"#version 450 core
- layout (binding = 0, $FORMAT$) uniform uimage2DMS imgIn;
- layout (binding = 1, $FORMAT$) uniform uimage2D imgOut;
- layout (local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
- void main()
- {
- uvec2 coords = gl_GlobalInvocationID.xy;
- ivec2 imageSz = imageSize(imgOut);
- if (int(coords.x) >= imageSz.x || int(coords.y) >= imageSz.y)
- {
- return;
- }
- int inSamples = imageSamples(imgIn);
- int samplesInXLog2 = 0;
- int samplesInYLog2 = 0;
- switch (inSamples)
- {
- case 2:
- samplesInXLog2 = 1;
- break;
- case 4:
- samplesInXLog2 = 1;
- samplesInYLog2 = 1;
- break;
- case 8:
- samplesInXLog2 = 2;
- samplesInYLog2 = 1;
- break;
- case 16:
- samplesInXLog2 = 2;
- samplesInYLog2 = 2;
- break;
- }
- int samplesInX = 1 << samplesInXLog2;
- int samplesInY = 1 << samplesInYLog2;
- int sampleIdx = (int(coords.x) & (samplesInX - 1)) | ((int(coords.y) & (samplesInY - 1)) << samplesInXLog2);
- uvec4 value = imageLoad(imgIn, ivec2(int(coords.x) >> samplesInXLog2, int(coords.y) >> samplesInYLog2), sampleIdx);
- imageStore(imgOut, ivec2(coords), value);
- }";
- private const string ComputeShaderNonMSToMS = @"#version 450 core
- layout (binding = 0, $FORMAT$) uniform uimage2D imgIn;
- layout (binding = 1, $FORMAT$) uniform uimage2DMS imgOut;
- layout (local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
- void main()
- {
- uvec2 coords = gl_GlobalInvocationID.xy;
- ivec2 imageSz = imageSize(imgIn);
- if (int(coords.x) >= imageSz.x || int(coords.y) >= imageSz.y)
- {
- return;
- }
- int outSamples = imageSamples(imgOut);
- int samplesInXLog2 = 0;
- int samplesInYLog2 = 0;
- switch (outSamples)
- {
- case 2:
- samplesInXLog2 = 1;
- break;
- case 4:
- samplesInXLog2 = 1;
- samplesInYLog2 = 1;
- break;
- case 8:
- samplesInXLog2 = 2;
- samplesInYLog2 = 1;
- break;
- case 16:
- samplesInXLog2 = 2;
- samplesInYLog2 = 2;
- break;
- }
- int samplesInX = 1 << samplesInXLog2;
- int samplesInY = 1 << samplesInYLog2;
- int sampleIdx = (int(coords.x) & (samplesInX - 1)) | ((int(coords.y) & (samplesInY - 1)) << samplesInXLog2);
- uvec4 value = imageLoad(imgIn, ivec2(coords));
- imageStore(imgOut, ivec2(int(coords.x) >> samplesInXLog2, int(coords.y) >> samplesInYLog2), sampleIdx, value);
- }";
- private readonly OpenGLRenderer _renderer;
- private int[] _msToNonMSProgramHandles;
- private int[] _nonMSToMSProgramHandles;
- public TextureCopyMS(OpenGLRenderer renderer)
- {
- _renderer = renderer;
- _msToNonMSProgramHandles = new int[5];
- _nonMSToMSProgramHandles = new int[5];
- }
- public void CopyMSToNonMS(ITextureInfo src, ITextureInfo dst, int srcLayer, int dstLayer, int depth)
- {
- TextureCreateInfo srcInfo = src.Info;
- TextureCreateInfo dstInfo = dst.Info;
- int srcHandle = CreateViewIfNeeded(src);
- int dstHandle = CreateViewIfNeeded(dst);
- int dstWidth = dstInfo.Width;
- int dstHeight = dstInfo.Height;
- GL.UseProgram(GetMSToNonMSShader(srcInfo.BytesPerPixel));
- for (int z = 0; z < depth; z++)
- {
- GL.BindImageTexture(0, srcHandle, 0, false, srcLayer + z, TextureAccess.ReadOnly, GetFormat(srcInfo.BytesPerPixel));
- GL.BindImageTexture(1, dstHandle, 0, false, dstLayer + z, TextureAccess.WriteOnly, GetFormat(dstInfo.BytesPerPixel));
- GL.DispatchCompute((dstWidth + 31) / 32, (dstHeight + 31) / 32, 1);
- }
- Pipeline pipeline = (Pipeline)_renderer.Pipeline;
- pipeline.RestoreProgram();
- pipeline.RestoreImages1And2();
- DestroyViewIfNeeded(src, srcHandle);
- DestroyViewIfNeeded(dst, dstHandle);
- }
- public void CopyNonMSToMS(ITextureInfo src, ITextureInfo dst, int srcLayer, int dstLayer, int depth)
- {
- TextureCreateInfo srcInfo = src.Info;
- TextureCreateInfo dstInfo = dst.Info;
- int srcHandle = CreateViewIfNeeded(src);
- int dstHandle = CreateViewIfNeeded(dst);
- int srcWidth = srcInfo.Width;
- int srcHeight = srcInfo.Height;
- GL.UseProgram(GetNonMSToMSShader(srcInfo.BytesPerPixel));
- for (int z = 0; z < depth; z++)
- {
- GL.BindImageTexture(0, srcHandle, 0, false, srcLayer + z, TextureAccess.ReadOnly, GetFormat(srcInfo.BytesPerPixel));
- GL.BindImageTexture(1, dstHandle, 0, false, dstLayer + z, TextureAccess.WriteOnly, GetFormat(dstInfo.BytesPerPixel));
- GL.DispatchCompute((srcWidth + 31) / 32, (srcHeight + 31) / 32, 1);
- }
- Pipeline pipeline = (Pipeline)_renderer.Pipeline;
- pipeline.RestoreProgram();
- pipeline.RestoreImages1And2();
- DestroyViewIfNeeded(src, srcHandle);
- DestroyViewIfNeeded(dst, dstHandle);
- }
- private static SizedInternalFormat GetFormat(int bytesPerPixel)
- {
- return bytesPerPixel switch
- {
- 1 => SizedInternalFormat.R8ui,
- 2 => SizedInternalFormat.R16ui,
- 4 => SizedInternalFormat.R32ui,
- 8 => SizedInternalFormat.Rg32ui,
- 16 => SizedInternalFormat.Rgba32ui,
- _ => throw new ArgumentException($"Invalid bytes per pixel {bytesPerPixel}.")
- };
- }
- private static int CreateViewIfNeeded(ITextureInfo texture)
- {
- // Binding sRGB textures as images doesn't work on NVIDIA,
- // we need to create and bind a RGBA view for it to work.
- if (texture.Info.Format == Format.R8G8B8A8Srgb)
- {
- int handle = GL.GenTexture();
- GL.TextureView(
- handle,
- texture.Info.Target.Convert(),
- texture.Storage.Handle,
- PixelInternalFormat.Rgba8,
- texture.FirstLevel,
- 1,
- texture.FirstLayer,
- texture.Info.GetLayers());
- return handle;
- }
- return texture.Handle;
- }
- private static void DestroyViewIfNeeded(ITextureInfo info, int handle)
- {
- if (info.Handle != handle)
- {
- GL.DeleteTexture(handle);
- }
- }
- private int GetMSToNonMSShader(int bytesPerPixel)
- {
- return GetShader(ComputeShaderMSToNonMS, _msToNonMSProgramHandles, bytesPerPixel);
- }
- private int GetNonMSToMSShader(int bytesPerPixel)
- {
- return GetShader(ComputeShaderNonMSToMS, _nonMSToMSProgramHandles, bytesPerPixel);
- }
- private int GetShader(string code, int[] programHandles, int bytesPerPixel)
- {
- int index = BitOperations.Log2((uint)bytesPerPixel);
- if (programHandles[index] == 0)
- {
- int csHandle = GL.CreateShader(ShaderType.ComputeShader);
- string format = new[] { "r8ui", "r16ui", "r32ui", "rg32ui", "rgba32ui" }[index];
- GL.ShaderSource(csHandle, code.Replace("$FORMAT$", format));
- GL.CompileShader(csHandle);
- int programHandle = GL.CreateProgram();
- GL.AttachShader(programHandle, csHandle);
- GL.LinkProgram(programHandle);
- GL.DetachShader(programHandle, csHandle);
- GL.DeleteShader(csHandle);
- GL.GetProgram(programHandle, GetProgramParameterName.LinkStatus, out int status);
- if (status == 0)
- {
- throw new Exception(GL.GetProgramInfoLog(programHandle));
- }
- programHandles[index] = programHandle;
- }
- return programHandles[index];
- }
- public void Dispose()
- {
- for (int i = 0; i < _msToNonMSProgramHandles.Length; i++)
- {
- if (_msToNonMSProgramHandles[i] != 0)
- {
- GL.DeleteProgram(_msToNonMSProgramHandles[i]);
- _msToNonMSProgramHandles[i] = 0;
- }
- }
- for (int i = 0; i < _nonMSToMSProgramHandles.Length; i++)
- {
- if (_nonMSToMSProgramHandles[i] != 0)
- {
- GL.DeleteProgram(_nonMSToMSProgramHandles[i]);
- _nonMSToMSProgramHandles[i] = 0;
- }
- }
- }
- }
- }
|