diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs index 5ea9ee2f6..91a1a728d 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs @@ -710,7 +710,12 @@ namespace Ryujinx.Graphics.Gpu.Image break; case Target.Texture2DMultisample: case Target.Texture2DMultisampleArray: - if (rhs.Target == Target.Texture2D || rhs.Target == Target.Texture2DArray) + // We don't support copy between multisample and non-multisample depth-stencil textures + // because there's no way to emulate that since most GPUs don't support writing a + // custom stencil value into the texture, among several other API limitations. + + if ((rhs.Target == Target.Texture2D || rhs.Target == Target.Texture2DArray) && + !rhs.FormatInfo.Format.IsDepthOrStencil()) { return TextureViewCompatibility.CopyOnly; } diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureView.cs b/Ryujinx.Graphics.OpenGL/Image/TextureView.cs index 3e7da6e36..68cd2d30f 100644 --- a/Ryujinx.Graphics.OpenGL/Image/TextureView.cs +++ b/Ryujinx.Graphics.OpenGL/Image/TextureView.cs @@ -139,7 +139,7 @@ namespace Ryujinx.Graphics.OpenGL.Image if (!destinationView.Target.IsMultisample() && Target.IsMultisample()) { - _renderer.TextureCopyMS.CopyMSToNonMS(this, destinationView, srcLayer, dstLayer,1); + _renderer.TextureCopyMS.CopyMSToNonMS(this, destinationView, srcLayer, dstLayer, 1); } else if (destinationView.Target.IsMultisample() && !Target.IsMultisample()) { diff --git a/Ryujinx.Graphics.Vulkan/HelperShader.cs b/Ryujinx.Graphics.Vulkan/HelperShader.cs index 0201de0ad..c842b9222 100644 --- a/Ryujinx.Graphics.Vulkan/HelperShader.cs +++ b/Ryujinx.Graphics.Vulkan/HelperShader.cs @@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.Vulkan private readonly IProgram _programColorBlitClearAlpha; private readonly IProgram _programColorClear; private readonly IProgram _programStrideChange; + private readonly IProgram _programColorCopyBetweenMsNonMs; public HelperShader(VulkanRenderer gd, Device device) { @@ -73,6 +74,20 @@ namespace Ryujinx.Graphics.Vulkan { new ShaderSource(ShaderBinaries.ChangeBufferStrideShaderSource, strideChangeBindings, ShaderStage.Compute, TargetLanguage.Spirv), }); + + var colorCopyMSBindings = new ShaderBindings( + new[] { 0 }, + Array.Empty(), + new[] { 0 }, + new[] { 0 }); + + _programColorCopyBetweenMsNonMs = gd.CreateProgramWithMinimalLayout(new[] + { + new ShaderSource(ShaderBinaries.ColorCopyBetweenMsNonMs, colorCopyMSBindings, ShaderStage.Compute, TargetLanguage.Spirv), + }, new[] + { + new SpecDescription((0, SpecConstType.Int32)) + }); } public void Blit( @@ -136,11 +151,7 @@ namespace Ryujinx.Graphics.Vulkan gd.BufferManager.SetData(bufferHandle, 0, region); - Span bufferRanges = stackalloc BufferRange[1]; - - bufferRanges[0] = new BufferRange(bufferHandle, 0, RegionBufferSize); - - _pipeline.SetUniformBuffers(1, bufferRanges); + _pipeline.SetUniformBuffers(1, stackalloc[] { new BufferRange(bufferHandle, 0, RegionBufferSize) }); Span viewports = stackalloc GAL.Viewport[1]; @@ -203,11 +214,7 @@ namespace Ryujinx.Graphics.Vulkan gd.BufferManager.SetData(bufferHandle, 0, clearColor); - Span bufferRanges = stackalloc BufferRange[1]; - - bufferRanges[0] = new BufferRange(bufferHandle, 0, ClearColorBufferSize); - - _pipeline.SetUniformBuffers(1, bufferRanges); + _pipeline.SetUniformBuffers(1, stackalloc[] { new BufferRange(bufferHandle, 0, ClearColorBufferSize) }); Span viewports = stackalloc GAL.Viewport[1]; @@ -269,11 +276,7 @@ namespace Ryujinx.Graphics.Vulkan gd.BufferManager.SetData(bufferHandle, 0, region); - Span bufferRanges = stackalloc BufferRange[1]; - - bufferRanges[0] = new BufferRange(bufferHandle, 0, RegionBufferSize); - - pipeline.SetUniformBuffers(1, bufferRanges); + pipeline.SetUniformBuffers(1, stackalloc[] { new BufferRange(bufferHandle, 0, RegionBufferSize) }); Span viewports = stackalloc GAL.Viewport[1]; @@ -351,11 +354,7 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetCommandBuffer(cbs); - Span cbRanges = stackalloc BufferRange[1]; - - cbRanges[0] = new BufferRange(bufferHandle, 0, ParamsBufferSize); - - _pipeline.SetUniformBuffers(0, cbRanges); + _pipeline.SetUniformBuffers(0, stackalloc[] { new BufferRange(bufferHandle, 0, ParamsBufferSize) }); Span> sbRanges = new Auto[2]; @@ -480,12 +479,207 @@ namespace Ryujinx.Graphics.Vulkan convertedCount * outputIndexSize); } + public void CopyMSToNonMS(VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, TextureView dst, int srcLayer, int dstLayer, int depth) + { + CopyMS(gd, cbs, src, dst, srcLayer, dstLayer, depth, src.Info.Samples, dst.Info.Width, dst.Info.Height); + } + + public void CopyNonMSToMS(VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, TextureView dst, int srcLayer, int dstLayer, int depth) + { + CopyMS(gd, cbs, src, dst, srcLayer, dstLayer, depth, dst.Info.Samples, src.Info.Width, src.Info.Height); + } + + private void CopyMS( + VulkanRenderer gd, + CommandBufferScoped cbs, + TextureView src, + TextureView dst, + int srcLayer, + int dstLayer, + int depth, + int samples, + int nonMSWidth, + int nonMSHeight) + { + const int ParamsBufferSize = 16; + + Span shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)]; + + // X and Y are the expected texture samples. + // Z and W are the actual texture samples used. + // They may differ if the GPU does not support the samples count requested and we had to use a lower amount. + (shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples); + (shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags((uint)samples)); + + var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize, false); + + gd.BufferManager.SetData(bufferHandle, 0, shaderParams); + + TextureView.InsertImageBarrier( + gd.Api, + cbs.CommandBuffer, + src.GetImage().Get(cbs).Value, + TextureStorage.DefaultAccessMask, + AccessFlags.AccessShaderReadBit, + PipelineStageFlags.PipelineStageAllCommandsBit, + PipelineStageFlags.PipelineStageComputeShaderBit, + ImageAspectFlags.ImageAspectColorBit, + src.FirstLayer + srcLayer, + src.FirstLevel, + depth, + 1); + + _pipeline.SetCommandBuffer(cbs); + + _pipeline.SetProgram(_programColorCopyBetweenMsNonMs); + + var format = GetFormat(src.Info.BytesPerPixel); + + int dispatchX = (nonMSWidth + 31) / 32; + int dispatchY = (nonMSHeight + 31) / 32; + + // Specialize shader. + bool srcIsMs = src.Info.Target.IsMultisample(); + int conversionType = srcIsMs ? src.Info.BytesPerPixel : -src.Info.BytesPerPixel; + _pipeline.Specialize(conversionType); + + _pipeline.SetUniformBuffers(0, stackalloc[] { new BufferRange(bufferHandle, 0, ParamsBufferSize) }); + + if (src.Info.Target == Target.Texture2DMultisampleArray || + dst.Info.Target == Target.Texture2DMultisampleArray) + { + for (int z = 0; z < depth; z++) + { + var srcView = Create2DLayerView(src, srcLayer + z, format); + var dstView = Create2DLayerView(dst, dstLayer + z); + + _pipeline.SetTextureAndSampler(ShaderStage.Compute, 0, srcView, null); + _pipeline.SetImage(0, dstView, format); + + _pipeline.DispatchCompute(dispatchX, dispatchY, 1); + + srcView.Release(); + dstView.Release(); + } + } + else + { + var srcView = Create2DLayerView(src, srcLayer, format); + + _pipeline.SetTextureAndSampler(ShaderStage.Compute, 0, srcView, null); + _pipeline.SetImage(0, dst, format); + + _pipeline.DispatchCompute(dispatchX, dispatchY, 1); + + srcView.Release(); + } + + gd.BufferManager.Delete(bufferHandle); + + _pipeline.Finish(gd, cbs); + + TextureView.InsertImageBarrier( + gd.Api, + cbs.CommandBuffer, + dst.GetImage().Get(cbs).Value, + AccessFlags.AccessShaderWriteBit, + TextureStorage.DefaultAccessMask, + PipelineStageFlags.PipelineStageComputeShaderBit, + PipelineStageFlags.PipelineStageAllCommandsBit, + ImageAspectFlags.ImageAspectColorBit, + dst.FirstLayer + dstLayer, + dst.FirstLevel, + depth, + 1); + } + + private static (int, int) GetSampleCountXYLog2(int samples) + { + int samplesInXLog2 = 0; + int samplesInYLog2 = 0; + + switch (samples) + { + case 2: // 2x1 + samplesInXLog2 = 1; + break; + case 4: // 2x2 + samplesInXLog2 = 1; + samplesInYLog2 = 1; + break; + case 8: // 4x2 + samplesInXLog2 = 2; + samplesInYLog2 = 1; + break; + case 16: // 4x4 + samplesInXLog2 = 2; + samplesInYLog2 = 2; + break; + case 32: // 8x4 + samplesInXLog2 = 3; + samplesInYLog2 = 2; + break; + case 64: // 8x8 + samplesInXLog2 = 3; + samplesInYLog2 = 3; + break; + } + + return (samplesInXLog2, samplesInYLog2); + } + + private static ITexture Create2DLayerView(TextureView from, int layer, GAL.Format? format = null) + { + var target = from.Info.Target switch + { + Target.Texture1DArray => Target.Texture1D, + Target.Texture2DArray => Target.Texture2D, + Target.Texture2DMultisampleArray => Target.Texture2DMultisample, + _ => from.Info.Target + }; + + var info = new TextureCreateInfo( + from.Info.Width, + from.Info.Height, + from.Info.Depth, + 1, + from.Info.Samples, + from.Info.BlockWidth, + from.Info.BlockHeight, + from.Info.BytesPerPixel, + format ?? from.Info.Format, + from.Info.DepthStencilMode, + target, + from.Info.SwizzleR, + from.Info.SwizzleG, + from.Info.SwizzleB, + from.Info.SwizzleA); + + return from.CreateView(info, layer, 0); + } + + private static GAL.Format GetFormat(int bytesPerPixel) + { + return bytesPerPixel switch + { + 1 => GAL.Format.R8Uint, + 2 => GAL.Format.R16Uint, + 4 => GAL.Format.R32Uint, + 8 => GAL.Format.R32G32Uint, + 16 => GAL.Format.R32G32B32A32Uint, + _ => throw new ArgumentException($"Invalid bytes per pixel {bytesPerPixel}.") + }; + } + protected virtual void Dispose(bool disposing) { if (disposing) { _programColorBlitClearAlpha.Dispose(); _programColorBlit.Dispose(); + _programColorClear.Dispose(); + _programStrideChange.Dispose(); + _programColorCopyBetweenMsNonMs.Dispose(); _samplerNearest.Dispose(); _samplerLinear.Dispose(); _pipeline.Dispose(); diff --git a/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/Ryujinx.Graphics.Vulkan/PipelineBase.cs index 2a376261e..f333c944b 100644 --- a/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -3,6 +3,8 @@ using Ryujinx.Graphics.Shader; using Silk.NET.Vulkan; using System; using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Vulkan { @@ -697,6 +699,18 @@ namespace Ryujinx.Graphics.Vulkan SignalStateChange(); } + public void Specialize(in T data) where T : unmanaged + { + var dataSpan = MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in data), 1)); + + if (!dataSpan.SequenceEqual(_newState.SpecializationData.Span)) + { + _newState.SpecializationData = new SpecData(dataSpan); + + SignalStateChange(); + } + } + protected virtual void SignalAttachmentChange() { } @@ -1188,14 +1202,7 @@ namespace Ryujinx.Graphics.Vulkan } } - var subpassDependency = new SubpassDependency( - 0, - 0, - PipelineStageFlags.PipelineStageAllGraphicsBit, - PipelineStageFlags.PipelineStageAllGraphicsBit, - AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit | AccessFlags.AccessColorAttachmentWriteBit, - AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit | AccessFlags.AccessShaderReadBit, - 0); + var subpassDependency = PipelineConverter.CreateSubpassDependency(); fixed (AttachmentDescription* pAttachmentDescs = attachmentDescs) { diff --git a/Ryujinx.Graphics.Vulkan/PipelineConverter.cs b/Ryujinx.Graphics.Vulkan/PipelineConverter.cs index 55d29ffa0..a01c5ad72 100644 --- a/Ryujinx.Graphics.Vulkan/PipelineConverter.cs +++ b/Ryujinx.Graphics.Vulkan/PipelineConverter.cs @@ -6,6 +6,9 @@ namespace Ryujinx.Graphics.Vulkan { static class PipelineConverter { + private const AccessFlags SubpassSrcAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit | AccessFlags.AccessColorAttachmentWriteBit; + private const AccessFlags SubpassDstAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit | AccessFlags.AccessShaderReadBit; + public static unsafe DisposableRenderPass ToRenderPass(this ProgramPipelineState state, VulkanRenderer gd, Device device) { const int MaxAttachments = Constants.MaxRenderTargets + 1; @@ -100,14 +103,7 @@ namespace Ryujinx.Graphics.Vulkan } } - var subpassDependency = new SubpassDependency( - 0, - 0, - PipelineStageFlags.PipelineStageAllGraphicsBit, - PipelineStageFlags.PipelineStageAllGraphicsBit, - AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit, - AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit, - 0); + var subpassDependency = CreateSubpassDependency(); fixed (AttachmentDescription* pAttachmentDescs = attachmentDescs) { @@ -128,6 +124,32 @@ namespace Ryujinx.Graphics.Vulkan } } + public static SubpassDependency CreateSubpassDependency() + { + return new SubpassDependency( + 0, + 0, + PipelineStageFlags.PipelineStageAllGraphicsBit, + PipelineStageFlags.PipelineStageAllGraphicsBit, + SubpassSrcAccessMask, + SubpassDstAccessMask, + 0); + } + + public unsafe static SubpassDependency2 CreateSubpassDependency2() + { + return new SubpassDependency2( + StructureType.SubpassDependency2, + null, + 0, + 0, + PipelineStageFlags.PipelineStageAllGraphicsBit, + PipelineStageFlags.PipelineStageAllGraphicsBit, + SubpassSrcAccessMask, + SubpassDstAccessMask, + 0); + } + public static PipelineState ToVulkanPipelineState(this ProgramPipelineState state, VulkanRenderer gd) { PipelineState pipeline = new PipelineState(); diff --git a/Ryujinx.Graphics.Vulkan/PipelineState.cs b/Ryujinx.Graphics.Vulkan/PipelineState.cs index d33bc8ce8..7b6a26490 100644 --- a/Ryujinx.Graphics.Vulkan/PipelineState.cs +++ b/Ryujinx.Graphics.Vulkan/PipelineState.cs @@ -312,6 +312,7 @@ namespace Ryujinx.Graphics.Vulkan public NativeArray Stages; public NativeArray StageRequiredSubgroupSizes; public PipelineLayout PipelineLayout; + public SpecData SpecializationData; public void Initialize() { @@ -334,7 +335,7 @@ namespace Ryujinx.Graphics.Vulkan ShaderCollection program, PipelineCache cache) { - if (program.TryGetComputePipeline(out var pipeline)) + if (program.TryGetComputePipeline(ref SpecializationData, out var pipeline)) { return pipeline; } @@ -354,20 +355,36 @@ namespace Ryujinx.Graphics.Vulkan Pipeline pipelineHandle = default; - gd.Api.CreateComputePipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle).ThrowOnError(); + bool hasSpec = program.SpecDescriptions != null; + + var desc = hasSpec ? program.SpecDescriptions[0] : SpecDescription.Empty; + + if (hasSpec && SpecializationData.Length < (int)desc.Info.DataSize) + { + throw new InvalidOperationException("Specialization data size does not match description"); + } + + fixed (SpecializationInfo* info = &desc.Info) + fixed (SpecializationMapEntry* map = desc.Map) + fixed (byte* data = SpecializationData.Span) + { + if (hasSpec) + { + info->PMapEntries = map; + info->PData = data; + pipelineCreateInfo.Stage.PSpecializationInfo = info; + } + + gd.Api.CreateComputePipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle).ThrowOnError(); + } pipeline = new Auto(new DisposablePipeline(gd.Api, device, pipelineHandle)); - program.AddComputePipeline(pipeline); + program.AddComputePipeline(ref SpecializationData, pipeline); return pipeline; } - public unsafe void DestroyComputePipeline(ShaderCollection program) - { - program.RemoveComputePipeline(); - } - public unsafe Auto CreateGraphicsPipeline( VulkanRenderer gd, Device device, diff --git a/Ryujinx.Graphics.Vulkan/ShaderCollection.cs b/Ryujinx.Graphics.Vulkan/ShaderCollection.cs index 82866f7b7..ab0ea2e95 100644 --- a/Ryujinx.Graphics.Vulkan/ShaderCollection.cs +++ b/Ryujinx.Graphics.Vulkan/ShaderCollection.cs @@ -26,6 +26,8 @@ namespace Ryujinx.Graphics.Vulkan public ProgramLinkStatus LinkStatus { get; private set; } + public readonly SpecDescription[] SpecDescriptions; + public bool IsLinked { get @@ -40,7 +42,7 @@ namespace Ryujinx.Graphics.Vulkan } private HashTableSlim> _graphicsPipelineCache; - private Auto _computePipeline; + private HashTableSlim> _computePipelineCache; private VulkanRenderer _gd; private Device _device; @@ -52,17 +54,24 @@ namespace Ryujinx.Graphics.Vulkan private Task _compileTask; private bool _firstBackgroundUse; - public ShaderCollection(VulkanRenderer gd, Device device, ShaderSource[] shaders, bool isMinimal = false) + public ShaderCollection(VulkanRenderer gd, Device device, ShaderSource[] shaders, SpecDescription[] specDescription = null, bool isMinimal = false) { _gd = gd; _device = device; + if (specDescription != null && specDescription.Length != shaders.Length) + { + throw new ArgumentException($"{nameof(specDescription)} array length must match {nameof(shaders)} array if provided"); + } + gd.Shaders.Add(this); var internalShaders = new Shader[shaders.Length]; _infos = new PipelineShaderStageCreateInfo[shaders.Length]; + SpecDescriptions = specDescription; + LinkStatus = ProgramLinkStatus.Incomplete; uint stages = 0; @@ -314,14 +323,9 @@ namespace Ryujinx.Graphics.Vulkan return null; } - public void AddComputePipeline(Auto pipeline) + public void AddComputePipeline(ref SpecData key, Auto pipeline) { - _computePipeline = pipeline; - } - - public void RemoveComputePipeline() - { - _computePipeline = null; + (_computePipelineCache ??= new()).Add(ref key, pipeline); } public void AddGraphicsPipeline(ref PipelineUid key, Auto pipeline) @@ -329,10 +333,20 @@ namespace Ryujinx.Graphics.Vulkan (_graphicsPipelineCache ??= new()).Add(ref key, pipeline); } - public bool TryGetComputePipeline(out Auto pipeline) + public bool TryGetComputePipeline(ref SpecData key, out Auto pipeline) { - pipeline = _computePipeline; - return pipeline != null; + if (_computePipelineCache == null) + { + pipeline = default; + return false; + } + + if (_computePipelineCache.TryGetValue(ref key, out pipeline)) + { + return true; + } + + return false; } public bool TryGetGraphicsPipeline(ref PipelineUid key, out Auto pipeline) @@ -390,7 +404,14 @@ namespace Ryujinx.Graphics.Vulkan } } - _computePipeline?.Dispose(); + if (_computePipelineCache != null) + { + foreach (Auto pipeline in _computePipelineCache.Values) + { + pipeline.Dispose(); + } + } + if (_dummyRenderPass.Value.Handle != 0) { _dummyRenderPass.Dispose(); diff --git a/Ryujinx.Graphics.Vulkan/Shaders/ColorCopyBetweenMsNonMs.comp b/Ryujinx.Graphics.Vulkan/Shaders/ColorCopyBetweenMsNonMs.comp new file mode 100644 index 000000000..c1ae2444c --- /dev/null +++ b/Ryujinx.Graphics.Vulkan/Shaders/ColorCopyBetweenMsNonMs.comp @@ -0,0 +1,89 @@ +#version 450 core + +// +ve for MsToNonMs, -ve for reverse +layout (constant_id = 0) const int convType = 0; + +layout (std140, binding = 0) uniform sample_counts_log2_in +{ + ivec4 sample_counts_log2; +}; + +#define R8_ID 1 +#define R16_ID 2 +#define R32_ID 4 +#define RG32_ID 8 +#define RGBA32_ID 16 + +#define R8_TYPE r8ui +#define R16_TYPE r16ui +#define R32_TYPE r32ui +#define RG32_TYPE rg32ui +#define RGBA32_TYPE rgba32ui + +#define DECLARE_BINDINGS(type) layout (set = 3, binding = 0, type##_TYPE) uniform uimage2DMS dstMS ## type; \ + layout (set = 3, binding = 0, type##_TYPE) uniform uimage2D dst ## type; + +#define CASE_SIZE(type) case type##_ID: imageSz = imageSize(dst ## type); break; + +#define CASE_CONVERT(type) case type##_ID: imageStore(dst ## type, ivec2(coords), texelFetch(srcMS, shiftedCoords, sampleIdx)); break; \ + case -type##_ID: imageStore(dstMS ## type, shiftedCoords, sampleIdx, texelFetch(src, ivec2(coords), 0)); break; + +// src tex +layout (set = 2, binding = 0) uniform usampler2DMS srcMS; +layout (set = 2, binding = 0) uniform usampler2D src; + +// dst img +DECLARE_BINDINGS(R8) +DECLARE_BINDINGS(R16) +DECLARE_BINDINGS(R32) +DECLARE_BINDINGS(RG32) +DECLARE_BINDINGS(RGBA32) + +layout (local_size_x = 32, local_size_y = 32, local_size_z = 1) in; + +void main() +{ + uvec2 coords = gl_GlobalInvocationID.xy; + + ivec2 imageSz = ivec2(0, 0); + + switch (convType) + { + case 0: break; + CASE_SIZE(R8 ) + CASE_SIZE(R16 ) + CASE_SIZE(R32 ) + CASE_SIZE(RG32 ) + CASE_SIZE(RGBA32) + default: + imageSz = textureSize(src, 0); + break; + } + + if (int(coords.x) >= imageSz.x || int(coords.y) >= imageSz.y) + { + return; + } + + int deltaX = sample_counts_log2.x - sample_counts_log2.z; + int deltaY = sample_counts_log2.y - sample_counts_log2.w; + int samplesInXLog2 = sample_counts_log2.z; + int samplesInYLog2 = sample_counts_log2.w; + int samplesInX = 1 << samplesInXLog2; + int samplesInY = 1 << samplesInYLog2; + int sampleIdx = ((int(coords.x) >> deltaX) & (samplesInX - 1)) | (((int(coords.y) >> deltaY) & (samplesInY - 1)) << samplesInXLog2); + + samplesInXLog2 = sample_counts_log2.x; + samplesInYLog2 = sample_counts_log2.y; + + ivec2 shiftedCoords = ivec2(int(coords.x) >> samplesInXLog2, int(coords.y) >> samplesInYLog2); + + switch (convType) + { + CASE_CONVERT(R8 ) + CASE_CONVERT(R16 ) + CASE_CONVERT(R32 ) + CASE_CONVERT(RG32 ) + CASE_CONVERT(RGBA32) + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics.Vulkan/Shaders/ShaderBinaries.cs b/Ryujinx.Graphics.Vulkan/Shaders/ShaderBinaries.cs index b7064f78c..9cc7e034e 100644 --- a/Ryujinx.Graphics.Vulkan/Shaders/ShaderBinaries.cs +++ b/Ryujinx.Graphics.Vulkan/Shaders/ShaderBinaries.cs @@ -551,5 +551,324 @@ namespace Ryujinx.Graphics.Vulkan.Shaders 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x35, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, }; + + public static readonly byte[] ColorCopyBetweenMsNonMs = new byte[] + { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x2D, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x1B, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x31, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x32, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, + 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x47, + 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x49, 0x6E, 0x76, 0x6F, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x49, + 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6E, 0x76, + 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x64, 0x73, 0x74, 0x52, 0x38, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x64, 0x73, 0x74, 0x52, 0x31, 0x36, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x2D, 0x00, 0x00, 0x00, + 0x64, 0x73, 0x74, 0x52, 0x33, 0x32, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x64, 0x73, 0x74, 0x52, 0x47, 0x33, 0x32, 0x00, 0x05, 0x00, 0x05, 0x00, 0x39, 0x00, 0x00, 0x00, + 0x64, 0x73, 0x74, 0x52, 0x47, 0x42, 0x41, 0x33, 0x32, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x73, 0x72, 0x63, 0x00, 0x05, 0x00, 0x08, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x73, 0x5F, 0x6C, 0x6F, + 0x67, 0x32, 0x5F, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, + 0x73, 0x5F, 0x6C, 0x6F, 0x67, 0x32, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x62, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x73, 0x72, 0x63, 0x4D, + 0x53, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0xBD, 0x00, 0x00, 0x00, 0x64, 0x73, 0x74, 0x4D, + 0x53, 0x52, 0x38, 0x00, 0x05, 0x00, 0x05, 0x00, 0xD2, 0x00, 0x00, 0x00, 0x64, 0x73, 0x74, 0x4D, + 0x53, 0x52, 0x31, 0x36, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0xE7, 0x00, 0x00, 0x00, + 0x64, 0x73, 0x74, 0x4D, 0x53, 0x52, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0xFC, 0x00, 0x00, 0x00, 0x64, 0x73, 0x74, 0x4D, 0x53, 0x52, 0x47, 0x33, 0x32, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x05, 0x00, 0x11, 0x01, 0x00, 0x00, 0x64, 0x73, 0x74, 0x4D, 0x53, 0x52, 0x47, 0x42, + 0x41, 0x33, 0x32, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x1C, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x33, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x33, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x39, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x39, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x62, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x62, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xBD, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xBD, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xD2, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xD2, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xE7, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xE7, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x11, 0x01, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x11, 0x01, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1D, 0x01, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x32, 0x00, 0x04, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, + 0x1F, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, + 0x3B, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x09, 0x00, 0x25, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x2C, 0x00, 0x00, 0x00, + 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x31, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, + 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, + 0x37, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, + 0x3B, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x09, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x03, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x3B, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x02, 0x00, 0x46, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x5F, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x5F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x61, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x61, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x63, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x03, 0x00, 0xB1, 0x00, 0x00, 0x00, + 0xB0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xB1, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0xB2, 0x00, 0x00, 0x00, 0xB3, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0xB8, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xBC, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0xBC, 0x00, 0x00, 0x00, + 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0xD0, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, + 0xD1, 0x00, 0x00, 0x00, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, + 0xE5, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x00, 0x00, 0x00, + 0x3B, 0x00, 0x04, 0x00, 0xE6, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x09, 0x00, 0xFA, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFA, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0xFB, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0F, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x10, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0x01, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x10, 0x01, 0x00, 0x00, + 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x1C, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x00, 0x00, + 0x1D, 0x01, 0x00, 0x00, 0x1C, 0x01, 0x00, 0x00, 0x1C, 0x01, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, + 0x1E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0x00, 0x03, 0x00, 0x47, 0x00, 0x00, 0x00, + 0x1F, 0x01, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x1F, 0x01, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x07, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x1D, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFB, 0x00, 0x0F, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x02, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x42, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x67, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x43, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0x1D, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x16, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0x1D, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0x1F, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x68, 0x00, 0x04, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0x1D, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x18, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x68, 0x00, 0x04, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0x1D, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0x2B, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x68, 0x00, 0x04, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0x1D, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0x31, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x68, 0x00, 0x04, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0x1D, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0x37, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x68, 0x00, 0x04, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0x1D, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x1D, 0x00, 0x00, 0x00, 0xF5, 0x00, 0x11, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x29, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x35, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, + 0x4A, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, + 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x00, 0x05, 0x00, 0x46, 0x00, 0x00, 0x00, + 0x4F, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x04, 0x00, + 0x46, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, + 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x51, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x55, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x2C, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAF, 0x00, 0x05, 0x00, 0x46, 0x00, 0x00, 0x00, + 0x59, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0x52, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x52, 0x00, 0x00, 0x00, 0xF5, 0x00, 0x07, 0x00, + 0x46, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, + 0x59, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x5C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00, + 0x5C, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x5B, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0x1E, 0x01, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, + 0x63, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x63, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, + 0x62, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x06, 0x00, 0x63, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x6C, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x63, 0x00, 0x00, 0x00, + 0x6E, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00, + 0x3D, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, + 0x82, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, + 0x6F, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x7D, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x05, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, + 0x82, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0xC7, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x88, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x05, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x8B, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x82, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0xC7, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x00, 0x00, + 0x8B, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x90, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x05, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, + 0xC3, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x9B, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, + 0x65, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, + 0x89, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xA1, 0x00, 0x00, 0x00, 0x9B, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, + 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0x00, 0x17, 0x00, 0x15, 0x00, 0x00, 0x00, + 0xAC, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA2, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xA3, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, + 0xA5, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xA6, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, + 0xA7, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, + 0xA9, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, + 0xAB, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0xA2, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0x1F, 0x00, 0x00, 0x00, 0xAD, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, + 0x10, 0x00, 0x00, 0x00, 0xAF, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0xB1, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, + 0xB0, 0x00, 0x00, 0x00, 0xB7, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x07, 0x00, + 0xB8, 0x00, 0x00, 0x00, 0xB9, 0x00, 0x00, 0x00, 0xB7, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x63, 0x00, 0x04, 0x00, 0xAD, 0x00, 0x00, 0x00, + 0xAF, 0x00, 0x00, 0x00, 0xB9, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0xAC, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x02, 0x00, 0xA3, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0xBB, 0x00, 0x00, 0x00, + 0xBE, 0x00, 0x00, 0x00, 0xBD, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0xC1, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xC3, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x07, 0x00, 0xB8, 0x00, 0x00, 0x00, + 0xC5, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x63, 0x00, 0x06, 0x00, 0xBE, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, + 0xC5, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0xAC, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0xA4, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0x25, 0x00, 0x00, 0x00, 0xC7, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, + 0x10, 0x00, 0x00, 0x00, 0xC9, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0xB1, 0x00, 0x00, 0x00, 0xCA, 0x00, 0x00, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, + 0xB0, 0x00, 0x00, 0x00, 0xCD, 0x00, 0x00, 0x00, 0xCA, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x07, 0x00, + 0xB8, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0xCD, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x63, 0x00, 0x04, 0x00, 0xC7, 0x00, 0x00, 0x00, + 0xC9, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0xAC, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x02, 0x00, 0xA5, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0xD0, 0x00, 0x00, 0x00, + 0xD3, 0x00, 0x00, 0x00, 0xD2, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0xD6, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xD8, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xD9, 0x00, 0x00, 0x00, 0xD6, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x07, 0x00, 0xB8, 0x00, 0x00, 0x00, + 0xDA, 0x00, 0x00, 0x00, 0xD9, 0x00, 0x00, 0x00, 0xD8, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x63, 0x00, 0x06, 0x00, 0xD3, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, + 0xDA, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0xAC, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0xA6, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0x2B, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, + 0x10, 0x00, 0x00, 0x00, 0xDE, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0xB1, 0x00, 0x00, 0x00, 0xDF, 0x00, 0x00, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, + 0xB0, 0x00, 0x00, 0x00, 0xE2, 0x00, 0x00, 0x00, 0xDF, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x07, 0x00, + 0xB8, 0x00, 0x00, 0x00, 0xE3, 0x00, 0x00, 0x00, 0xE2, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x63, 0x00, 0x04, 0x00, 0xDC, 0x00, 0x00, 0x00, + 0xDE, 0x00, 0x00, 0x00, 0xE3, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0xAC, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x02, 0x00, 0xA7, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0xE5, 0x00, 0x00, 0x00, + 0xE8, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0xEB, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xED, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xEE, 0x00, 0x00, 0x00, 0xEB, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x07, 0x00, 0xB8, 0x00, 0x00, 0x00, + 0xEF, 0x00, 0x00, 0x00, 0xEE, 0x00, 0x00, 0x00, 0xED, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x63, 0x00, 0x06, 0x00, 0xE8, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, + 0xEF, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0xAC, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0xA8, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0x31, 0x00, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, + 0x10, 0x00, 0x00, 0x00, 0xF3, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0xB1, 0x00, 0x00, 0x00, 0xF4, 0x00, 0x00, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, + 0xB0, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x00, 0x00, 0xF4, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x07, 0x00, + 0xB8, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x63, 0x00, 0x04, 0x00, 0xF1, 0x00, 0x00, 0x00, + 0xF3, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0xAC, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x02, 0x00, 0xA9, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0xFA, 0x00, 0x00, 0x00, + 0xFD, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x02, 0x01, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x5F, 0x00, 0x07, 0x00, 0xB8, 0x00, 0x00, 0x00, + 0x04, 0x01, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x63, 0x00, 0x06, 0x00, 0xFD, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, + 0x04, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0xAC, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0xAA, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0x37, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0xB1, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, + 0xB0, 0x00, 0x00, 0x00, 0x0C, 0x01, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x5F, 0x00, 0x07, 0x00, + 0xB8, 0x00, 0x00, 0x00, 0x0D, 0x01, 0x00, 0x00, 0x0C, 0x01, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x63, 0x00, 0x04, 0x00, 0x06, 0x01, 0x00, 0x00, + 0x08, 0x01, 0x00, 0x00, 0x0D, 0x01, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0xAC, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x02, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0F, 0x01, 0x00, 0x00, + 0x12, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x15, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x17, 0x01, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x18, 0x01, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x5F, 0x00, 0x07, 0x00, 0xB8, 0x00, 0x00, 0x00, + 0x19, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x63, 0x00, 0x06, 0x00, 0x12, 0x01, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, + 0x19, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0xAC, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0xAC, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, + 0x1E, 0x01, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x1E, 0x01, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, + 0x38, 0x00, 0x01, 0x00, + }; } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Vulkan/SpecInfo.cs b/Ryujinx.Graphics.Vulkan/SpecInfo.cs new file mode 100644 index 000000000..83a34cde0 --- /dev/null +++ b/Ryujinx.Graphics.Vulkan/SpecInfo.cs @@ -0,0 +1,103 @@ +using Silk.NET.Vulkan; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Vulkan +{ + public enum SpecConstType + { + Bool32, + Int16, + Int32, + Int64, + Float16, + Float32, + Float64 + } + + sealed class SpecDescription + { + public readonly SpecializationInfo Info; + public readonly SpecializationMapEntry[] Map; + + // For mapping a simple packed struct or single entry + public SpecDescription(params (uint Id, SpecConstType Type)[] description) + { + int count = description.Length; + Map = new SpecializationMapEntry[count]; + + uint structSize = 0; + + for (int i = 0; i < count; ++i) + { + var typeSize = SizeOf(description[i].Type); + Map[i] = new SpecializationMapEntry(description[i].Id, structSize, typeSize); + structSize += typeSize; + } + + Info = new SpecializationInfo() + { + DataSize = structSize, + MapEntryCount = (uint)count + }; + } + + // For advanced mapping with overlapping or staggered fields + public SpecDescription(SpecializationMapEntry[] map) + { + int count = map.Length; + Map = map; + + uint structSize = 0; + for (int i = 0; i < count; ++i) + { + structSize = Math.Max(structSize, map[i].Offset + (uint)map[i].Size); + } + + Info = new SpecializationInfo() + { + DataSize = structSize, + MapEntryCount = (uint)map.Length + }; + } + + private static uint SizeOf(SpecConstType type) => type switch + { + SpecConstType.Int16 or SpecConstType.Float16 => 2, + SpecConstType.Bool32 or SpecConstType.Int32 or SpecConstType.Float32 => 4, + SpecConstType.Int64 or SpecConstType.Float64 => 8, + _ => throw new ArgumentOutOfRangeException(nameof(type)) + }; + + private SpecDescription() + { + Info = new(); + } + + public static readonly SpecDescription Empty = new(); + } + + readonly struct SpecData : IRefEquatable + { + private readonly byte[] _data; + private readonly int _hash; + + public int Length => _data.Length; + public ReadOnlySpan Span => _data.AsSpan(); + public override int GetHashCode() => _hash; + + public SpecData(ReadOnlySpan data) + { + _data = new byte[data.Length]; + data.CopyTo(_data); + + var hc = new HashCode(); + hc.AddBytes(data); + _hash = hc.ToHashCode(); + } + + public override bool Equals(object obj) => obj is SpecData other && Equals(other); + public bool Equals(ref SpecData other) => _data.AsSpan().SequenceEqual(other._data); + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics.Vulkan/TextureCopy.cs b/Ryujinx.Graphics.Vulkan/TextureCopy.cs index 05e110936..d14c2a324 100644 --- a/Ryujinx.Graphics.Vulkan/TextureCopy.cs +++ b/Ryujinx.Graphics.Vulkan/TextureCopy.cs @@ -355,5 +355,122 @@ namespace Ryujinx.Graphics.Vulkan dstLayers, levels); } + + public unsafe static void ResolveDepthStencil( + VulkanRenderer gd, + Device device, + CommandBufferScoped cbs, + TextureView src, + TextureView dst) + { + var dsAttachmentReference = new AttachmentReference2(StructureType.AttachmentReference2, null, 0, ImageLayout.General); + var dsResolveAttachmentReference = new AttachmentReference2(StructureType.AttachmentReference2, null, 1, ImageLayout.General); + + var subpassDsResolve = new SubpassDescriptionDepthStencilResolve() + { + SType = StructureType.SubpassDescriptionDepthStencilResolve, + PDepthStencilResolveAttachment = &dsResolveAttachmentReference, + DepthResolveMode = ResolveModeFlags.ResolveModeSampleZeroBit, + StencilResolveMode = ResolveModeFlags.ResolveModeSampleZeroBit + }; + + var subpass = new SubpassDescription2() + { + SType = StructureType.SubpassDescription2, + PipelineBindPoint = PipelineBindPoint.Graphics, + PDepthStencilAttachment = &dsAttachmentReference, + PNext = &subpassDsResolve + }; + + AttachmentDescription2[] attachmentDescs = new AttachmentDescription2[2]; + + attachmentDescs[0] = new AttachmentDescription2( + StructureType.AttachmentDescription2, + null, + 0, + src.VkFormat, + TextureStorage.ConvertToSampleCountFlags((uint)src.Info.Samples), + AttachmentLoadOp.Load, + AttachmentStoreOp.Store, + AttachmentLoadOp.Load, + AttachmentStoreOp.Store, + ImageLayout.General, + ImageLayout.General); + + attachmentDescs[1] = new AttachmentDescription2( + StructureType.AttachmentDescription2, + null, + 0, + dst.VkFormat, + TextureStorage.ConvertToSampleCountFlags((uint)dst.Info.Samples), + AttachmentLoadOp.Load, + AttachmentStoreOp.Store, + AttachmentLoadOp.Load, + AttachmentStoreOp.Store, + ImageLayout.General, + ImageLayout.General); + + var subpassDependency = PipelineConverter.CreateSubpassDependency2(); + + fixed (AttachmentDescription2* pAttachmentDescs = attachmentDescs) + { + var renderPassCreateInfo = new RenderPassCreateInfo2() + { + SType = StructureType.RenderPassCreateInfo2, + PAttachments = pAttachmentDescs, + AttachmentCount = (uint)attachmentDescs.Length, + PSubpasses = &subpass, + SubpassCount = 1, + PDependencies = &subpassDependency, + DependencyCount = 1 + }; + + gd.Api.CreateRenderPass2(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError(); + + using var rp = new Auto(new DisposableRenderPass(gd.Api, device, renderPass)); + + ImageView* attachments = stackalloc ImageView[2]; + + var srcView = src.GetImageViewForAttachment(); + var dstView = dst.GetImageViewForAttachment(); + + attachments[0] = srcView.Get(cbs).Value; + attachments[1] = dstView.Get(cbs).Value; + + var framebufferCreateInfo = new FramebufferCreateInfo() + { + SType = StructureType.FramebufferCreateInfo, + RenderPass = rp.Get(cbs).Value, + AttachmentCount = 2, + PAttachments = attachments, + Width = (uint)src.Width, + Height = (uint)src.Height, + Layers = (uint)src.Layers + }; + + gd.Api.CreateFramebuffer(device, framebufferCreateInfo, null, out var framebuffer).ThrowOnError(); + using var fb = new Auto(new DisposableFramebuffer(gd.Api, device, framebuffer), null, new[] { srcView, dstView }); + + var renderArea = new Rect2D(null, new Extent2D((uint)src.Info.Width, (uint)src.Info.Height)); + var clearValue = new ClearValue(); + + var renderPassBeginInfo = new RenderPassBeginInfo() + { + SType = StructureType.RenderPassBeginInfo, + RenderPass = rp.Get(cbs).Value, + Framebuffer = fb.Get(cbs).Value, + RenderArea = renderArea, + PClearValues = &clearValue, + ClearValueCount = 1 + }; + + // The resolve operation happens at the end of the subpass, so let's just do a begin/end + // to resolve the depth-stencil texture. + // TODO: Do speculative resolve and part of the same render pass as the draw to avoid + // ending the current render pass? + gd.Api.CmdBeginRenderPass(cbs.CommandBuffer, renderPassBeginInfo, SubpassContents.Inline); + gd.Api.CmdEndRenderPass(cbs.CommandBuffer); + } + } } } diff --git a/Ryujinx.Graphics.Vulkan/TextureView.cs b/Ryujinx.Graphics.Vulkan/TextureView.cs index 10d0ef05d..f47e431b1 100644 --- a/Ryujinx.Graphics.Vulkan/TextureView.cs +++ b/Ryujinx.Graphics.Vulkan/TextureView.cs @@ -169,12 +169,15 @@ namespace Ryujinx.Graphics.Vulkan var srcImage = src.GetImage().Get(cbs).Value; var dstImage = dst.GetImage().Get(cbs).Value; - if (src.Info.Target.IsMultisample()) + if (!dst.Info.Target.IsMultisample() && Info.Target.IsMultisample()) { - int depth = Math.Min(src.Info.Depth, dst.Info.Depth - firstLayer); - int levels = Math.Min(src.Info.Levels, dst.Info.Levels - firstLevel); - - CopyMSToNonMS(_gd, cbs, src, dst, srcImage, dstImage, 0, firstLayer, 0, firstLevel, depth, levels); + int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer); + _gd.HelperShader.CopyMSToNonMS(_gd, cbs, src, dst, 0, firstLayer, layers); + } + else if (dst.Info.Target.IsMultisample() && !Info.Target.IsMultisample()) + { + int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer); + _gd.HelperShader.CopyNonMSToMS(_gd, cbs, src, dst, 0, firstLayer, layers); } else { @@ -213,9 +216,13 @@ namespace Ryujinx.Graphics.Vulkan var srcImage = src.GetImage().Get(cbs).Value; var dstImage = dst.GetImage().Get(cbs).Value; - if (src.Info.Target.IsMultisample()) + if (!dst.Info.Target.IsMultisample() && Info.Target.IsMultisample()) { - CopyMSToNonMS(_gd, cbs, src, dst, srcImage, dstImage, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1); + _gd.HelperShader.CopyMSToNonMS(_gd, cbs, src, dst, srcLayer, dstLayer, 1); + } + else if (dst.Info.Target.IsMultisample() && !Info.Target.IsMultisample()) + { + _gd.HelperShader.CopyNonMSToMS(_gd, cbs, src, dst, srcLayer, dstLayer, 1); } else { @@ -239,142 +246,6 @@ namespace Ryujinx.Graphics.Vulkan } } - private static void CopyMSToNonMS( - VulkanRenderer gd, - CommandBufferScoped cbs, - TextureView src, - TextureView dst, - Image srcImage, - Image dstImage, - int srcLayer, - int dstLayer, - int srcLevel, - int dstLevel, - int layers, - int levels) - { - bool differentFormats = src.Info.Format != dst.Info.Format; - - var target = src.Info.Target switch - { - Target.Texture2D => Target.Texture2DMultisample, - Target.Texture2DArray => Target.Texture2DMultisampleArray, - Target.Texture2DMultisampleArray => Target.Texture2DArray, - _ => Target.Texture2D - }; - - var intermmediateTarget = differentFormats ? dst.Info.Target : target; - using var intermmediate = CreateIntermmediateTexture(gd, src, ref dst._info, intermmediateTarget, layers, levels); - var intermmediateImage = intermmediate.GetImage().Get(cbs).Value; - - if (differentFormats) - { - // If the formats are different, the resolve would perform format conversion. - // So we need yet another intermmediate texture and do a copy to reinterpret the - // data into the correct (destination) format, without doing any sort of conversion. - using var intermmediate2 = CreateIntermmediateTexture(gd, src, ref src._info, target, layers, levels); - var intermmediate2Image = intermmediate2.GetImage().Get(cbs).Value; - - TextureCopy.Copy( - gd.Api, - cbs.CommandBuffer, - srcImage, - intermmediate2Image, - src.Info, - intermmediate2.Info, - src.FirstLayer, - 0, - src.FirstLevel, - 0, - srcLayer, - 0, - srcLevel, - 0, - layers, - levels); - - TextureCopy.Copy( - gd.Api, - cbs.CommandBuffer, - intermmediate2Image, - intermmediateImage, - intermmediate2.Info, - intermmediate.Info, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - layers, - levels); - } - else - { - TextureCopy.Copy( - gd.Api, - cbs.CommandBuffer, - srcImage, - intermmediateImage, - src.Info, - intermmediate.Info, - src.FirstLayer, - 0, - src.FirstLevel, - 0, - srcLayer, - 0, - srcLevel, - 0, - layers, - levels); - } - - var srcRegion = new Extents2D(0, 0, src.Width, src.Height); - var dstRegion = new Extents2D(0, 0, dst.Width, dst.Height); - - TextureCopy.Blit( - gd.Api, - cbs.CommandBuffer, - intermmediateImage, - dstImage, - intermmediate.Info, - dst.Info, - srcRegion, - dstRegion, - 0, - dst.FirstLevel + dstLevel, - 0, - dst.FirstLayer + dstLayer, - layers, - levels, - true, - ImageAspectFlags.ImageAspectColorBit, - ImageAspectFlags.ImageAspectColorBit); - } - - private static TextureView CreateIntermmediateTexture(VulkanRenderer gd, TextureView src, ref TextureCreateInfo formatInfo, Target target, int depth, int levels) - { - return gd.CreateTextureView(new GAL.TextureCreateInfo( - src.Width, - src.Height, - depth, - levels, - 1, - formatInfo.BlockWidth, - formatInfo.BlockHeight, - formatInfo.BytesPerPixel, - formatInfo.Format, - DepthStencilMode.Depth, - target, - SwizzleComponent.Red, - SwizzleComponent.Green, - SwizzleComponent.Blue, - SwizzleComponent.Alpha), 1f); - } - public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter) { var dst = (TextureView)destination; @@ -422,23 +293,32 @@ namespace Ryujinx.Graphics.Vulkan src.Height == dst.Height && src.VkFormat == dst.VkFormat) { - TextureCopy.Copy( - _gd.Api, - cbs.CommandBuffer, - src.GetImage().Get(cbs).Value, - dst.GetImage().Get(cbs).Value, - src.Info, - dst.Info, - src.FirstLayer, - dst.FirstLayer, - src.FirstLevel, - dst.FirstLevel, - 0, - 0, - 0, - 0, - layers, - levels); + if (src.Info.Samples > 1 && src.Info.Samples != dst.Info.Samples && src.Info.Format.IsDepthOrStencil()) + { + // CmdResolveImage does not support depth-stencil resolve, so we need to use an alternative path + // for those textures. + TextureCopy.ResolveDepthStencil(_gd, _device, cbs, src, dst); + } + else + { + TextureCopy.Copy( + _gd.Api, + cbs.CommandBuffer, + src.GetImage().Get(cbs).Value, + dst.GetImage().Get(cbs).Value, + src.Info, + dst.Info, + src.FirstLayer, + dst.FirstLayer, + src.FirstLevel, + dst.FirstLevel, + 0, + 0, + 0, + 0, + layers, + levels); + } return; } diff --git a/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs b/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs index 5d8accd27..e54eef4f9 100644 --- a/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs +++ b/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs @@ -1,4 +1,4 @@ -using Ryujinx.Common.Configuration; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; using Silk.NET.Vulkan; @@ -393,6 +393,7 @@ namespace Ryujinx.Graphics.Vulkan ShaderClipDistance = true, ShaderFloat64 = supportedFeatures.ShaderFloat64, ShaderImageGatherExtended = true, + ShaderStorageImageMultisample = supportedFeatures.ShaderStorageImageMultisample, // ShaderStorageImageReadWithoutFormat = true, // ShaderStorageImageWriteWithoutFormat = true, TessellationShader = true, diff --git a/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index ef089c32e..ef1360e75 100644 --- a/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -287,9 +287,9 @@ namespace Ryujinx.Graphics.Vulkan } } - internal ShaderCollection CreateProgramWithMinimalLayout(ShaderSource[] sources) + internal ShaderCollection CreateProgramWithMinimalLayout(ShaderSource[] sources, SpecDescription[] specDescription = null) { - return new ShaderCollection(this, _device, sources, isMinimal: true); + return new ShaderCollection(this, _device, sources, specDescription: specDescription, isMinimal: true); } public ISampler CreateSampler(GAL.SamplerCreateInfo info)