From f82309fa2dd46d4339e0709ab835d927fd25361b Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 2 Nov 2022 18:17:19 -0300 Subject: [PATCH] Vulkan: Implement multisample <-> non-multisample copies and depth-stencil resolve (#3723) * Vulkan: Implement multisample <-> non-multisample copies and depth-stencil resolve * FramebufferParams is no longer required there * Implement Specialization Constants and merge CopyMS Shaders (#15) * Vulkan: Initial Specialization Constants * Replace with specialized helper shader * Reimplement everything Fix nonexistant interaction with Ryu pipeline caching Decouple specialization info from data and relocate them Generalize mapping and add type enum to better match spv types Use local fixed scopes instead of global unmanaged allocs * Fix misses in initial implementation Use correct info variable in Create2DLayerView Add ShaderStorageImageMultisample to required feature set * Use texture for source image * No point in using ReadOnlyMemory * Apply formatting feedback Co-authored-by: gdkchan * Apply formatting suggestions on shader source Co-authored-by: gdkchan Co-authored-by: gdkchan * Support conversion with samples count that does not match the requested count, other minor changes Co-authored-by: mageven <62494521+mageven@users.noreply.github.com> --- .../Image/TextureCompatibility.cs | 7 +- Ryujinx.Graphics.OpenGL/Image/TextureView.cs | 2 +- Ryujinx.Graphics.Vulkan/HelperShader.cs | 234 +++++++++++-- Ryujinx.Graphics.Vulkan/PipelineBase.cs | 23 +- Ryujinx.Graphics.Vulkan/PipelineConverter.cs | 38 ++- Ryujinx.Graphics.Vulkan/PipelineState.cs | 33 +- Ryujinx.Graphics.Vulkan/ShaderCollection.cs | 47 ++- .../Shaders/ColorCopyBetweenMsNonMs.comp | 89 +++++ .../Shaders/ShaderBinaries.cs | 319 ++++++++++++++++++ Ryujinx.Graphics.Vulkan/SpecInfo.cs | 103 ++++++ Ryujinx.Graphics.Vulkan/TextureCopy.cs | 117 +++++++ Ryujinx.Graphics.Vulkan/TextureView.cs | 200 +++-------- .../VulkanInitialization.cs | 3 +- Ryujinx.Graphics.Vulkan/VulkanRenderer.cs | 4 +- 14 files changed, 997 insertions(+), 222 deletions(-) create mode 100644 Ryujinx.Graphics.Vulkan/Shaders/ColorCopyBetweenMsNonMs.comp create mode 100644 Ryujinx.Graphics.Vulkan/SpecInfo.cs diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs index 5ea9ee2f..91a1a728 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 3e7da6e3..68cd2d30 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 0201de0a..c842b922 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 2a376261..f333c944 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 55d29ffa..a01c5ad7 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 d33bc8ce..7b6a2649 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 82866f7b..ab0ea2e9 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 00000000..c1ae2444 --- /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 b7064f78..9cc7e034 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 00000000..83a34cde --- /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 05e11093..d14c2a32 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 10d0ef05..f47e431b 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 5d8accd2..e54eef4f 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 ef089c32..ef1360e7 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)