From 79aee1df43ef43ae76a5b72494967446bd072f8b Mon Sep 17 00:00:00 2001 From: Remi Palandri Date: Wed, 2 Mar 2022 23:42:16 -0800 Subject: [PATCH] full implementation of compute msaa-to-buffer --- renderdoc/CMakeLists.txt | 4 + renderdoc/data/embedded_files.h | 4 + renderdoc/data/glsl/glsl_globals.h | 11 + renderdoc/data/glsl/vk_buffer2ms.comp | 120 +++ renderdoc/data/glsl/vk_depthbuf2ms.frag | 113 +++ renderdoc/data/glsl/vk_depthms2buffer.comp | 116 +++ renderdoc/data/glsl/vk_ms2buffer.comp | 120 +++ renderdoc/data/renderdoc.rc | 4 + renderdoc/data/resource.h | 4 + renderdoc/driver/vulkan/CMakeLists.txt | 2 +- .../driver/vulkan/renderdoc_vulkan.vcxproj | 2 +- .../vulkan/renderdoc_vulkan.vcxproj.filters | 6 +- renderdoc/driver/vulkan/vk_debug.cpp | 195 ++--- renderdoc/driver/vulkan/vk_debug.h | 44 +- renderdoc/driver/vulkan/vk_initstate.cpp | 277 ++---- renderdoc/driver/vulkan/vk_manager.h | 3 - .../driver/vulkan/vk_msaa_array_conv.cpp | 808 ------------------ .../driver/vulkan/vk_msaa_buffer_conv.cpp | 729 ++++++++++++++++ renderdoc/driver/vulkan/vk_replay.cpp | 351 ++++---- renderdoc/driver/vulkan/vk_shader_cache.cpp | 29 +- renderdoc/driver/vulkan/vk_shader_cache.h | 13 +- .../driver/vulkan/wrappers/vk_get_funcs.cpp | 2 +- .../driver/vulkan/wrappers/vk_misc_funcs.cpp | 2 +- .../vulkan/wrappers/vk_resource_funcs.cpp | 6 +- 24 files changed, 1576 insertions(+), 1389 deletions(-) create mode 100644 renderdoc/data/glsl/vk_buffer2ms.comp create mode 100644 renderdoc/data/glsl/vk_depthbuf2ms.frag create mode 100644 renderdoc/data/glsl/vk_depthms2buffer.comp create mode 100644 renderdoc/data/glsl/vk_ms2buffer.comp delete mode 100644 renderdoc/driver/vulkan/vk_msaa_array_conv.cpp create mode 100644 renderdoc/driver/vulkan/vk_msaa_buffer_conv.cpp diff --git a/renderdoc/CMakeLists.txt b/renderdoc/CMakeLists.txt index f838d014e..caacfdc4c 100644 --- a/renderdoc/CMakeLists.txt +++ b/renderdoc/CMakeLists.txt @@ -446,6 +446,10 @@ set(data data/glsl/deptharr2ms.frag data/glsl/depthms2arr.frag data/glsl/discard.frag + data/glsl/vk_ms2buffer.comp + data/glsl/vk_depthms2buffer.comp + data/glsl/vk_buffer2ms.comp + data/glsl/vk_depthbuf2ms.frag data/sourcecodepro.ttf driver/vulkan/renderdoc.json) diff --git a/renderdoc/data/embedded_files.h b/renderdoc/data/embedded_files.h index bfaaf13ad..9787913f9 100644 --- a/renderdoc/data/embedded_files.h +++ b/renderdoc/data/embedded_files.h @@ -69,5 +69,9 @@ DECLARE_EMBED(glsl_pixelhistory_primid_frag); DECLARE_EMBED(glsl_shaderdebug_sample_vert); DECLARE_EMBED(glsl_texremap_frag); DECLARE_EMBED(glsl_discard_frag); +DECLARE_EMBED(glsl_vk_ms2buffer_comp); +DECLARE_EMBED(glsl_vk_depthms2buffer_comp); +DECLARE_EMBED(glsl_vk_buffer2ms_comp); +DECLARE_EMBED(glsl_vk_depthbuf2ms_frag); #undef DECLARE_EMBED diff --git a/renderdoc/data/glsl/glsl_globals.h b/renderdoc/data/glsl/glsl_globals.h index 676e6c089..51cfadf61 100644 --- a/renderdoc/data/glsl/glsl_globals.h +++ b/renderdoc/data/glsl/glsl_globals.h @@ -84,6 +84,17 @@ precision highp int; #define CUBEMAP_FACE_POS_Z 4 #define CUBEMAP_FACE_NEG_Z 5 +// used in depthms2buffer.comp to define enum-format mapping +#define SHADER_D16_UNORM 0 +#define SHADER_D16_UNORM_S8_UINT 1 +#define SHADER_X8_D24_UNORM_PACK32 2 +#define SHADER_D24_UNORM_S8_UINT 3 +#define SHADER_D32_SFLOAT 4 +#define SHADER_D32_SFLOAT_S8_UINT 5 + +// divide MS<->buffer workgroups by 64 +#define MS_DISPATCH_LOCAL_SIZE 64 + #if !defined(__cplusplus) vec3 CalcCubeCoord(vec2 uv, int face) diff --git a/renderdoc/data/glsl/vk_buffer2ms.comp b/renderdoc/data/glsl/vk_buffer2ms.comp new file mode 100644 index 000000000..74153c807 --- /dev/null +++ b/renderdoc/data/glsl/vk_buffer2ms.comp @@ -0,0 +1,120 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2020-2022 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "glsl_globals.h" + +layout(local_size_x = MS_DISPATCH_LOCAL_SIZE, local_size_y = 1, local_size_z = 1) in; + +layout(binding = 2, std430) readonly buffer srcBuf +{ + uint srcData[]; +}; + +layout(binding = 3) writeonly uniform uimage2DMSArray dstMS; + +layout(push_constant) uniform multisamplePush +{ + int texWidth; + int sliceOffset; + int sampleOffset; + int byteSize; + int maxInvocationID; +} +mscopy; + +#define texWidth (mscopy.texWidth) +#define sliceOffset (mscopy.sliceOffset) +#define sampleOffset (mscopy.sampleOffset) +#define byteSize (mscopy.byteSize) +#define maxInvocationID (mscopy.maxInvocationID) + +void main() +{ + uint idx = gl_GlobalInvocationID.x; + + int slice = sliceOffset; + int sampleIdx = sampleOffset; + + if(int(idx) >= maxInvocationID) + { + return; + } + + uvec4 data; + if(byteSize == 1) + { + data.x = srcData[idx]; + int pxIdx = int(idx * 4); + int x0 = (pxIdx + 0) % texWidth; + int y0 = (pxIdx + 0) / texWidth; + int x1 = (pxIdx + 1) % texWidth; + int y1 = (pxIdx + 1) / texWidth; + int x2 = (pxIdx + 2) % texWidth; + int y2 = (pxIdx + 2) / texWidth; + int x3 = (pxIdx + 3) % texWidth; + int y3 = (pxIdx + 3) / texWidth; + + imageStore(dstMS, ivec3(x0, y0, slice), sampleIdx, uvec4((data.x >> 0) & 0xFF, 0, 0, 0)); + imageStore(dstMS, ivec3(x1, y1, slice), sampleIdx, uvec4((data.x >> 8) & 0xFF, 0, 0, 0)); + imageStore(dstMS, ivec3(x2, y2, slice), sampleIdx, uvec4((data.x >> 16) & 0xFF, 0, 0, 0)); + imageStore(dstMS, ivec3(x3, y3, slice), sampleIdx, uvec4((data.x >> 24) & 0xFF, 0, 0, 0)); + } + else if(byteSize == 2) + { + data.x = srcData[idx]; + int pxIdx = int(idx * 2); + int x0 = (pxIdx + 0) % texWidth; + int y0 = (pxIdx + 0) / texWidth; + int x1 = (pxIdx + 1) % texWidth; + int y1 = (pxIdx + 1) / texWidth; + + imageStore(dstMS, ivec3(x0, y0, slice), sampleIdx, uvec4((data.x >> 0) & 0xFFFF, 0, 0, 0)); + imageStore(dstMS, ivec3(x1, y1, slice), sampleIdx, uvec4((data.x >> 16) & 0xFFFF, 0, 0, 0)); + } + else if(byteSize == 4) + { + int x0 = int(idx) % texWidth; + int y0 = int(idx) / texWidth; + data.x = srcData[idx]; + imageStore(dstMS, ivec3(x0, y0, slice), sampleIdx, data); + } + else if(byteSize == 8) + { + int x0 = int(idx) % texWidth; + int y0 = int(idx) / texWidth; + data.x = srcData[idx * 2]; + data.y = srcData[idx * 2 + 1]; + imageStore(dstMS, ivec3(x0, y0, slice), sampleIdx, data); + } + else if(byteSize == 16) + { + int x0 = int(idx) % texWidth; + int y0 = int(idx) / texWidth; + data.x = srcData[idx * 4]; + data.y = srcData[idx * 4 + 1]; + data.z = srcData[idx * 4 + 2]; + data.w = srcData[idx * 4 + 3]; + imageStore(dstMS, ivec3(x0, y0, slice), sampleIdx, data); + } +} diff --git a/renderdoc/data/glsl/vk_depthbuf2ms.frag b/renderdoc/data/glsl/vk_depthbuf2ms.frag new file mode 100644 index 000000000..7de801530 --- /dev/null +++ b/renderdoc/data/glsl/vk_depthbuf2ms.frag @@ -0,0 +1,113 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2020-2022 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "glsl_globals.h" + +layout(binding = 2, std430) readonly buffer srcBuf +{ + uint srcData[]; +}; + +layout(push_constant) uniform multisamplePush +{ + int numMultiSamples; + int format; + int currentSlice; + uint currentStencil; + int textureWidth; + int textureHeight; +} +mscopy; + +#define MAX_D16 ((1 << 16) - 1) +#define MAX_D24 ((1 << 24) - 1) + +#define D16ToFloat(depth) (float(depth) / float(MAX_D16)) +#define D24ToFloat(depth) (float(depth) / float(MAX_D24)) + +#define numMultiSamples (mscopy.numMultiSamples) +#define format (mscopy.format) +#define currentSlice (mscopy.currentSlice) +#define currentStencil (mscopy.currentStencil) +#define textureWidth (mscopy.textureWidth) +#define textureHeight (mscopy.textureHeight) + +void main() +{ + ivec3 srcCoord = + ivec3(int(gl_FragCoord.x), int(gl_FragCoord.y), currentSlice *numMultiSamples + gl_SampleID); + uint idx = srcCoord.x + textureWidth * (srcCoord.y + (textureHeight * srcCoord.z)); + + float depth = 0; + uint stencil = 0; + if(format == SHADER_D16_UNORM) + { + uint data = srcData[idx / 2]; + if(idx % 2 == 0) + { + depth = D16ToFloat(data & 0xFFFF); + } + else + { + depth = D16ToFloat((data >> 16) & 0xFFFF); + } + } + else if(format == SHADER_D16_UNORM_S8_UINT) + { + uint data = srcData[idx]; + depth = D16ToFloat(data & 0xFFFF); + stencil = (data >> 16) & 0xFF; + } + else if(format == SHADER_X8_D24_UNORM_PACK32) + { + uint data = srcData[idx]; + depth = D24ToFloat(data & 0xFFFFFF); + } + else if(format == SHADER_D24_UNORM_S8_UINT) + { + uint data = srcData[idx]; + depth = D24ToFloat(data & 0xFFFFFF); + stencil = (data >> 24) & 0xFF; + } + else if(format == SHADER_D32_SFLOAT) + { + uint data = srcData[idx]; + depth = uintBitsToFloat(data); + } + else if(format == SHADER_D32_SFLOAT_S8_UINT) + { + uint data = srcData[idx * 2]; + depth = uintBitsToFloat(data); + uint stencilData = srcData[idx * 2 + 1]; + stencil = stencilData & 0xFF; + } + + if(currentStencil < 256u) + { + if(stencil != currentStencil) + discard; + } + + gl_FragDepth = depth; +} diff --git a/renderdoc/data/glsl/vk_depthms2buffer.comp b/renderdoc/data/glsl/vk_depthms2buffer.comp new file mode 100644 index 000000000..d4e101646 --- /dev/null +++ b/renderdoc/data/glsl/vk_depthms2buffer.comp @@ -0,0 +1,116 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2020-2022 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "glsl_globals.h" +#extension GL_EXT_samplerless_texture_functions : require + +layout(local_size_x = MS_DISPATCH_LOCAL_SIZE, local_size_y = 1, local_size_z = 1) in; + +layout(binding = 0) uniform texture2DMSArray srcDepthMS; +layout(binding = 1) uniform utexture2DMSArray srcStencilMS; + +layout(binding = 2, std430) writeonly buffer dstBuf +{ + uint result[]; +}; + +#define MAX_D16 ((1 << 16) - 1) +#define MAX_D24 ((1 << 24) - 1) + +#define floatToD16(depth) uint(MAX_D16 *depth) +#define floatToD24(depth) uint(MAX_D24 *depth) + +layout(push_constant) uniform multisamplePush +{ + int textureWidth; + int baseSlice; + int baseSample; + int format; + int maxInvocationID; +} +mscopy; + +#define textureWidth (mscopy.textureWidth) +#define baseSlice (mscopy.baseSlice) +#define baseSample (mscopy.baseSample) +#define format (mscopy.format) +#define maxInvocationID (mscopy.maxInvocationID) + +void main() +{ + int slice = baseSlice; + int sampleIdx = baseSample; + uint idx = gl_GlobalInvocationID.x; + if(int(idx) >= maxInvocationID) + { + return; + } + + int x0 = int(idx) % textureWidth; + int y0 = int(idx) / textureWidth; + ivec3 coord = ivec3(x0, y0, slice); + + // For D16, we need to sample 2 pixels at a time + if(format == SHADER_D16_UNORM) + { + int pxIdx = int(idx * 2); + int x0 = (pxIdx + 0) % textureWidth; + int y0 = (pxIdx + 0) / textureWidth; + int x1 = (pxIdx + 1) % textureWidth; + int y1 = (pxIdx + 1) / textureWidth; + + vec2 depth = vec2(texelFetch(srcDepthMS, ivec3(x0, y0, slice), sampleIdx).x, + texelFetch(srcDepthMS, ivec3(x1, y1, slice), sampleIdx).x); + result[idx] = (floatToD16(depth.x) << 0) | (floatToD16(depth.y) << 16); + } + else if(format == SHADER_D16_UNORM_S8_UINT) + { + float depth = texelFetch(srcDepthMS, coord, sampleIdx).x; + uint stencil = texelFetch(srcStencilMS, coord, sampleIdx).x; + result[idx] = (floatToD16(depth) << 0) | (stencil << 16); + } + else if(format == SHADER_X8_D24_UNORM_PACK32) + { + float depth = texelFetch(srcDepthMS, coord, sampleIdx).x; + result[idx] = (floatToD24(depth) << 0); + } + else if(format == SHADER_D24_UNORM_S8_UINT) + { + float depth = texelFetch(srcDepthMS, coord, sampleIdx).x; + uint stencil = texelFetch(srcStencilMS, coord, sampleIdx).x; + result[idx] = (floatToD24(depth) << 0) | (stencil << 24); + } + else if(format == SHADER_D32_SFLOAT) + { + float depth = texelFetch(srcDepthMS, coord, sampleIdx).x; + result[idx] = floatBitsToUint(depth); + } + else if(format == SHADER_D32_SFLOAT_S8_UINT) + { + float depth = texelFetch(srcDepthMS, coord, sampleIdx).x; + uint stencil = texelFetch(srcStencilMS, coord, sampleIdx).x; + result[idx * 2 + 0] = floatBitsToUint(depth); + result[idx * 2 + 1] = stencil; + } +} diff --git a/renderdoc/data/glsl/vk_ms2buffer.comp b/renderdoc/data/glsl/vk_ms2buffer.comp new file mode 100644 index 000000000..291f884d9 --- /dev/null +++ b/renderdoc/data/glsl/vk_ms2buffer.comp @@ -0,0 +1,120 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2020-2022 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "glsl_globals.h" +#extension GL_EXT_samplerless_texture_functions : require + +layout(local_size_x = MS_DISPATCH_LOCAL_SIZE, local_size_y = 1, local_size_z = 1) in; + +layout(binding = 0) uniform utexture2DMSArray srcMS; +// binding = 1 used as stencil read in the depth-stencil copy fragment shaders + +layout(binding = 2, std430) writeonly buffer dstBuf +{ + uint result[]; +}; + +layout(push_constant) uniform multisamplePush +{ + int textureWidth; + int baseSlice; + int baseSample; + int byteSize; + int maxInvocationID; +} +mscopy; + +#define textureWidth (mscopy.textureWidth) +#define baseSlice (mscopy.baseSlice) +#define baseSample (mscopy.baseSample) +#define byteSize (mscopy.byteSize) +#define maxInvocationID (mscopy.maxInvocationID) + +void main() +{ + int slice = baseSlice; + int sampleIdx = baseSample; + uint idx = gl_GlobalInvocationID.x; + if(int(idx) >= maxInvocationID) + { + return; + } + + // for byteSize < 4, we sample multiple pixels to fill a single output buffer element + if(byteSize == 1) + { + int pxIdx = int(idx * 4); + int x0 = (pxIdx + 0) % textureWidth; + int y0 = (pxIdx + 0) / textureWidth; + int x1 = (pxIdx + 1) % textureWidth; + int y1 = (pxIdx + 1) / textureWidth; + int x2 = (pxIdx + 2) % textureWidth; + int y2 = (pxIdx + 2) / textureWidth; + int x3 = (pxIdx + 3) % textureWidth; + int y3 = (pxIdx + 3) / textureWidth; + + uvec4 data = uvec4(texelFetch(srcMS, ivec3(x0, y0, slice), sampleIdx).x, + texelFetch(srcMS, ivec3(x1, y1, slice), sampleIdx).x, + texelFetch(srcMS, ivec3(x2, y2, slice), sampleIdx).x, + texelFetch(srcMS, ivec3(x3, y3, slice), sampleIdx).x); + result[idx] = (data.x << 0 | data.y << 8 | data.z << 16 | data.w << 24); + } + else if(byteSize == 2) + { + int pxIdx = int(idx * 2); + int x0 = (pxIdx + 0) % textureWidth; + int y0 = (pxIdx + 0) / textureWidth; + int x1 = (pxIdx + 1) % textureWidth; + int y1 = (pxIdx + 1) / textureWidth; + + uvec2 data = uvec2(texelFetch(srcMS, ivec3(x0, y0, slice), sampleIdx).x, + texelFetch(srcMS, ivec3(x1, y1, slice), sampleIdx).x); + result[idx] = (data.x << 0 | data.y << 16); + } + else if(byteSize == 4) + { + int x0 = int(idx) % textureWidth; + int y0 = int(idx) / textureWidth; + uint data = texelFetch(srcMS, ivec3(x0, y0, slice), sampleIdx).x; + result[idx] = data; + } + else if(byteSize == 8) + { + int x0 = int(idx) % textureWidth; + int y0 = int(idx) / textureWidth; + uvec2 data = texelFetch(srcMS, ivec3(x0, y0, slice), sampleIdx).xy; + result[idx * 2] = data.x; + result[idx * 2 + 1] = data.y; + } + else if(byteSize == 16) + { + int x0 = int(idx) % textureWidth; + int y0 = int(idx) / textureWidth; + uvec4 data = texelFetch(srcMS, ivec3(x0, y0, slice), sampleIdx); + result[idx * 4] = data.x; + result[idx * 4 + 1] = data.y; + result[idx * 4 + 2] = data.z; + result[idx * 4 + 3] = data.w; + } +} diff --git a/renderdoc/data/renderdoc.rc b/renderdoc/data/renderdoc.rc index 20ede9f0a..a731a4f88 100644 --- a/renderdoc/data/renderdoc.rc +++ b/renderdoc/data/renderdoc.rc @@ -174,6 +174,10 @@ RESOURCE_glsl_glsl_globals_h TYPE_EMBED "glsl/glsl_globals.h" RESOURCE_glsl_texremap_frag TYPE_EMBED "glsl/texremap.frag" RESOURCE_glsl_shaderdebug_sample_vert TYPE_EMBED "glsl/shaderdebug_sample.vert" RESOURCE_glsl_discard_frag TYPE_EMBED "glsl/discard.frag" +RESOURCE_glsl_vk_ms2buffer_comp TYPE_EMBED "glsl/vk_ms2buffer.comp" +RESOURCE_glsl_vk_depthms2buffer_comp TYPE_EMBED "glsl/vk_depthms2buffer.comp" +RESOURCE_glsl_vk_buffer2ms_comp TYPE_EMBED "glsl/vk_buffer2ms.comp" +RESOURCE_glsl_vk_depthbuf2ms_frag TYPE_EMBED "glsl/vk_depthbuf2ms.frag" #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// diff --git a/renderdoc/data/resource.h b/renderdoc/data/resource.h index 906e13840..c45021f3a 100644 --- a/renderdoc/data/resource.h +++ b/renderdoc/data/resource.h @@ -60,6 +60,10 @@ #define RESOURCE_glsl_pixelhistory_primid_frag 444 #define RESOURCE_glsl_shaderdebug_sample_vert 445 #define RESOURCE_glsl_discard_frag 446 +#define RESOURCE_glsl_vk_ms2buffer_comp 447 +#define RESOURCE_glsl_vk_depthms2buffer_comp 448 +#define RESOURCE_glsl_vk_buffer2ms_comp 449 +#define RESOURCE_glsl_vk_depthbuf2ms_frag 450 // Next default values for new objects // diff --git a/renderdoc/driver/vulkan/CMakeLists.txt b/renderdoc/driver/vulkan/CMakeLists.txt index 28a24be0c..ce30786a3 100644 --- a/renderdoc/driver/vulkan/CMakeLists.txt +++ b/renderdoc/driver/vulkan/CMakeLists.txt @@ -10,7 +10,7 @@ set(sources vk_postvs.cpp vk_shader_feedback.cpp vk_overlay.cpp - vk_msaa_array_conv.cpp + vk_msaa_buffer_conv.cpp vk_outputwindow.cpp vk_rendermesh.cpp vk_rendertexture.cpp diff --git a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj index fb6d4b6ec..1dabd623d 100644 --- a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj +++ b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj @@ -109,9 +109,9 @@ true + - diff --git a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters index baadbebc2..7abbafeab 100644 --- a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters +++ b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters @@ -118,9 +118,6 @@ Replay - - Replay - Replay @@ -151,6 +148,9 @@ Replay + + Replay + diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 647973667..e078b3173 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -371,55 +371,61 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver) VulkanShaderCache *shaderCache = driver->GetShaderCache(); - VkDescriptorPoolSize poolTypes[] = { - {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2 * ARRAY_COUNT(m_ArrayMSDescSet)}, - {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 * ARRAY_COUNT(m_ArrayMSDescSet)}, + ////////////////////////////////////////////////////////////////// + // Color MS <-> Buffer copy (via compute) + VkDescriptorPoolSize bufferPoolTypes[] = { + {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 2 * ARRAY_COUNT(m_BufferMSDescSet)}, + {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1 * ARRAY_COUNT(m_BufferMSDescSet)}, + {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 * ARRAY_COUNT(m_BufferMSDescSet)}, }; - VkDescriptorPoolCreateInfo poolInfo = { + VkDescriptorPoolCreateInfo bufferPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, NULL, 0, - ARRAY_COUNT(m_ArrayMSDescSet), - ARRAY_COUNT(poolTypes), - &poolTypes[0], + ARRAY_COUNT(m_BufferMSDescSet), + ARRAY_COUNT(bufferPoolTypes), + &bufferPoolTypes[0], }; - CREATE_OBJECT(m_ArrayMSSampler, VK_FILTER_NEAREST); - - rm->SetInternalResource(GetResID(m_ArrayMSSampler)); - - vkr = m_pDriver->vkCreateDescriptorPool(dev, &poolInfo, NULL, &m_ArrayMSDescriptorPool); + vkr = m_pDriver->vkCreateDescriptorPool(dev, &bufferPoolInfo, NULL, &m_BufferMSDescriptorPool); CheckVkResult(vkr); - rm->SetInternalResource(GetResID(m_ArrayMSDescriptorPool)); + rm->SetInternalResource(GetResID(m_BufferMSDescriptorPool)); - CREATE_OBJECT(m_ArrayMSDescSetLayout, + CREATE_OBJECT(m_BufferMSDescSetLayout, { - {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, NULL}, - {1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, NULL}, - {2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_ALL, NULL}, + {0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, NULL}, + {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, NULL}, + {2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, NULL}, + {3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_ALL, NULL}, }); - rm->SetInternalResource(GetResID(m_ArrayMSDescSetLayout)); + rm->SetInternalResource(GetResID(m_BufferMSDescSetLayout)); - CREATE_OBJECT(m_ArrayMSPipeLayout, m_ArrayMSDescSetLayout, sizeof(Vec4u)); + CREATE_OBJECT(m_BufferMSPipeLayout, m_BufferMSDescSetLayout, sizeof(Vec4u) * 2); - rm->SetInternalResource(GetResID(m_ArrayMSPipeLayout)); + rm->SetInternalResource(GetResID(m_BufferMSPipeLayout)); + + CREATE_OBJECT(m_MS2BufferPipe, m_BufferMSPipeLayout, + shaderCache->GetBuiltinModule(BuiltinShader::MS2BufferCS)); + CREATE_OBJECT(m_DepthMS2BufferPipe, m_BufferMSPipeLayout, + shaderCache->GetBuiltinModule(BuiltinShader::DepthMS2BufferCS)); + CREATE_OBJECT(m_Buffer2MSPipe, m_BufferMSPipeLayout, + shaderCache->GetBuiltinModule(BuiltinShader::Buffer2MSCS)); + + rm->SetInternalResource(GetResID(m_MS2BufferPipe)); + rm->SetInternalResource(GetResID(m_DepthMS2BufferPipe)); + rm->SetInternalResource(GetResID(m_Buffer2MSPipe)); + + for(size_t i = 0; i < ARRAY_COUNT(m_BufferMSDescSet); i++) + { + CREATE_OBJECT(m_BufferMSDescSet[i], m_BufferMSDescriptorPool, m_BufferMSDescSetLayout); + rm->SetInternalResource(GetResID(m_BufferMSDescSet[i])); + } ////////////////////////////////////////////////////////////////// - // Color MS to Array copy (via compute) - - CREATE_OBJECT(m_MS2ArrayPipe, m_ArrayMSPipeLayout, - shaderCache->GetBuiltinModule(BuiltinShader::MS2ArrayCS)); - CREATE_OBJECT(m_Array2MSPipe, m_ArrayMSPipeLayout, - shaderCache->GetBuiltinModule(BuiltinShader::Array2MSCS)); - - rm->SetInternalResource(GetResID(m_MS2ArrayPipe)); - rm->SetInternalResource(GetResID(m_Array2MSPipe)); - - ////////////////////////////////////////////////////////////////// - // Depth MS to Array copy (via graphics) + // Depth MS to Buffer copy (via compute) // need a dummy UINT texture to fill the binding when we don't have a stencil aspect to copy. // unfortunately there's no single guaranteed UINT format that can be sampled as MSAA, so we try a @@ -473,13 +479,6 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver) if(imgprops.sampleCounts == VK_SAMPLE_COUNT_1_BIT) continue; - vkr = driver->vkCreateImage(driver->GetDev(), &imInfo, NULL, &m_DummyStencilImage[0]); - CheckVkResult(vkr); - - NameVulkanObject(m_DummyStencilImage[0], "m_DummyStencilImage[0]"); - - rm->SetInternalResource(GetResID(m_DummyStencilImage[0])); - imInfo.samples = VK_SAMPLE_COUNT_2_BIT; // MoltenVK seems to only support 4/8 samples and not 2... @@ -498,27 +497,20 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver) RDCASSERT(imgprops.sampleCounts & imInfo.samples, imgprops.sampleCounts, imInfo.samples); - vkr = driver->vkCreateImage(driver->GetDev(), &imInfo, NULL, &m_DummyStencilImage[1]); + vkr = driver->vkCreateImage(driver->GetDev(), &imInfo, NULL, &m_DummyStencilImage); CheckVkResult(vkr); - NameVulkanObject(m_DummyStencilImage[1], "m_DummyStencilImage[1]"); + NameVulkanObject(m_DummyStencilImage, "m_DummyStencilImage"); - rm->SetInternalResource(GetResID(m_DummyStencilImage[1])); + rm->SetInternalResource(GetResID(m_DummyStencilImage)); - VkMemoryRequirements mrq[2] = {}; - driver->vkGetImageMemoryRequirements(driver->GetDev(), m_DummyStencilImage[0], &mrq[0]); - driver->vkGetImageMemoryRequirements(driver->GetDev(), m_DummyStencilImage[1], &mrq[1]); - - uint32_t memoryTypeBits = (mrq[0].memoryTypeBits & mrq[1].memoryTypeBits); - - // assume we have some memory type available in common - RDCASSERT(memoryTypeBits, mrq[0].memoryTypeBits, mrq[1].memoryTypeBits); + VkMemoryRequirements mrq = {}; + driver->vkGetImageMemoryRequirements(driver->GetDev(), m_DummyStencilImage, &mrq); // allocate memory VkMemoryAllocateInfo allocInfo = { - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, - AlignUp(mrq[0].size, mrq[1].alignment) + mrq[1].size, - driver->GetGPULocalMemoryIndex(memoryTypeBits), + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, mrq.size, + driver->GetGPULocalMemoryIndex(mrq.memoryTypeBits), }; vkr = driver->vkAllocateMemory(driver->GetDev(), &allocInfo, NULL, &m_DummyStencilMemory); @@ -529,19 +521,14 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver) rm->SetInternalResource(GetResID(m_DummyStencilMemory)); - vkr = - driver->vkBindImageMemory(driver->GetDev(), m_DummyStencilImage[0], m_DummyStencilMemory, 0); - CheckVkResult(vkr); - - vkr = driver->vkBindImageMemory(driver->GetDev(), m_DummyStencilImage[1], m_DummyStencilMemory, - AlignUp(mrq[0].size, mrq[1].alignment)); + vkr = driver->vkBindImageMemory(driver->GetDev(), m_DummyStencilImage, m_DummyStencilMemory, 0); CheckVkResult(vkr); VkImageViewCreateInfo viewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, NULL, 0, - m_DummyStencilImage[0], + m_DummyStencilImage, VK_IMAGE_VIEW_TYPE_2D_ARRAY, f, {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, @@ -551,21 +538,12 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver) }, }; - vkr = driver->vkCreateImageView(driver->GetDev(), &viewInfo, NULL, &m_DummyStencilView[0]); + vkr = driver->vkCreateImageView(driver->GetDev(), &viewInfo, NULL, &m_DummyStencilView); CheckVkResult(vkr); - NameVulkanObject(m_DummyStencilView[0], "m_DummyStencilView[0]"); + NameVulkanObject(m_DummyStencilView, "m_DummyStencilView"); - rm->SetInternalResource(GetResID(m_DummyStencilView[0])); - - viewInfo.image = m_DummyStencilImage[1]; - - vkr = driver->vkCreateImageView(driver->GetDev(), &viewInfo, NULL, &m_DummyStencilView[1]); - CheckVkResult(vkr); - - NameVulkanObject(m_DummyStencilView[0], "m_DummyStencilView[1]"); - - rm->SetInternalResource(GetResID(m_DummyStencilView[1])); + rm->SetInternalResource(GetResID(m_DummyStencilView)); VkCommandBuffer cmd = driver->GetNextCmd(); @@ -588,33 +566,22 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver) VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, - Unwrap(m_DummyStencilImage[0]), + Unwrap(m_DummyStencilImage), {barrierAspectMask, 0, 1, 0, 1}, }; DoPipelineBarrier(cmd, 1, &barrier); - barrier.image = Unwrap(m_DummyStencilImage[1]); - - DoPipelineBarrier(cmd, 1, &barrier); - ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); break; } - if(m_DummyStencilImage[0] == VK_NULL_HANDLE) + if(m_DummyStencilImage == VK_NULL_HANDLE) { RDCERR("Couldn't find any integer format we could generate a dummy multisampled image with"); } - for(size_t i = 0; i < ARRAY_COUNT(m_ArrayMSDescSet); i++) - { - CREATE_OBJECT(m_ArrayMSDescSet[i], m_ArrayMSDescriptorPool, m_ArrayMSDescSetLayout); - - rm->SetInternalResource(GetResID(m_ArrayMSDescSet[i])); - } - VkFormat formats[] = { VK_FORMAT_D16_UNORM, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, @@ -624,8 +591,6 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver) VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_16_BIT, }; - RDCCOMPILE_ASSERT(ARRAY_COUNT(m_DepthMS2ArrayPipe) == ARRAY_COUNT(formats), - "Array count mismatch"); RDCCOMPILE_ASSERT(ARRAY_COUNT(m_DepthArray2MSPipe) == ARRAY_COUNT(formats), "Array count mismatch"); RDCCOMPILE_ASSERT(ARRAY_COUNT(m_DepthArray2MSPipe[0]) == ARRAY_COUNT(sampleCounts), @@ -645,20 +610,22 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver) continue; } - VkRenderPass depthMS2ArrayRP = VK_NULL_HANDLE; - - CREATE_OBJECT(depthMS2ArrayRP, formats[f], VK_SAMPLE_COUNT_1_BIT, rpLayout); + if(!m_pDriver->GetDeviceEnabledFeatures().sampleRateShading) + { + RDCDEBUG("No depth Array -> MSAA copies can be supported without sample rate shading"); + continue; + } ConciseGraphicsPipeline depthPipeInfo = { - depthMS2ArrayRP, - m_ArrayMSPipeLayout, + VK_NULL_HANDLE, + m_BufferMSPipeLayout, shaderCache->GetBuiltinModule(BuiltinShader::BlitVS), - shaderCache->GetBuiltinModule(BuiltinShader::DepthMS2ArrayFS), + shaderCache->GetBuiltinModule(BuiltinShader::DepthBuf2MSFS), {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_STENCIL_REFERENCE}, VK_SAMPLE_COUNT_1_BIT, - false, // sampleRateShading - true, // depthEnable - true, // stencilEnable + true, // sampleRateShading + true, // depthEnable + true, // stencilEnable VK_STENCIL_OP_REPLACE, false, // colourOutput false, // blendEnable @@ -667,18 +634,6 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver) 0xf, // writeMask }; - CREATE_OBJECT(m_DepthMS2ArrayPipe[f], depthPipeInfo); - - rm->SetInternalResource(GetResID(m_DepthMS2ArrayPipe[f])); - - m_pDriver->vkDestroyRenderPass(dev, depthMS2ArrayRP, NULL); - - if(!m_pDriver->GetDeviceEnabledFeatures().sampleRateShading) - { - RDCDEBUG("No depth Array -> MSAA copies can be supported without sample rate shading"); - continue; - } - for(size_t s = 0; s < ARRAY_COUNT(sampleCounts); s++) { // if this sample count isn't supported, don't create it @@ -694,10 +649,8 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver) CREATE_OBJECT(depthArray2MSRP, formats[f], sampleCounts[s], rpLayout); - depthPipeInfo.fragment = shaderCache->GetBuiltinModule(BuiltinShader::DepthArray2MSFS); depthPipeInfo.renderPass = depthArray2MSRP; depthPipeInfo.sampleCount = sampleCounts[s]; - depthPipeInfo.sampleRateShading = true; CREATE_OBJECT(m_DepthArray2MSPipe[f][s], depthPipeInfo); @@ -788,19 +741,18 @@ VulkanDebugManager::~VulkanDebugManager() for(uint32_t i = 0; i < VKMeshDisplayPipelines::ePipe_Count; i++) m_pDriver->vkDestroyPipeline(dev, it->second.pipes[i], NULL); - m_pDriver->vkDestroyDescriptorPool(dev, m_ArrayMSDescriptorPool, NULL); - m_pDriver->vkDestroySampler(dev, m_ArrayMSSampler, NULL); + m_pDriver->vkDestroyDescriptorPool(dev, m_BufferMSDescriptorPool, NULL); - m_pDriver->vkDestroyImageView(dev, m_DummyStencilView[0], NULL); - m_pDriver->vkDestroyImageView(dev, m_DummyStencilView[1], NULL); - m_pDriver->vkDestroyImage(dev, m_DummyStencilImage[0], NULL); - m_pDriver->vkDestroyImage(dev, m_DummyStencilImage[1], NULL); + m_pDriver->vkDestroyImageView(dev, m_DummyStencilView, NULL); + m_pDriver->vkDestroyImage(dev, m_DummyStencilImage, NULL); m_pDriver->vkFreeMemory(dev, m_DummyStencilMemory, NULL); - m_pDriver->vkDestroyDescriptorSetLayout(dev, m_ArrayMSDescSetLayout, NULL); - m_pDriver->vkDestroyPipelineLayout(dev, m_ArrayMSPipeLayout, NULL); - m_pDriver->vkDestroyPipeline(dev, m_Array2MSPipe, NULL); - m_pDriver->vkDestroyPipeline(dev, m_MS2ArrayPipe, NULL); + m_pDriver->vkDestroyDescriptorSetLayout(dev, m_BufferMSDescSetLayout, NULL); + m_pDriver->vkDestroyPipelineLayout(dev, m_BufferMSPipeLayout, NULL); + m_pDriver->vkDestroyPipeline(dev, m_Buffer2MSPipe, NULL); + + m_pDriver->vkDestroyPipeline(dev, m_MS2BufferPipe, NULL); + m_pDriver->vkDestroyPipeline(dev, m_DepthMS2BufferPipe, NULL); m_pDriver->vkDestroyDescriptorPool(dev, m_DiscardPool, NULL); m_pDriver->vkDestroyPipelineLayout(dev, m_DiscardLayout, NULL); @@ -827,9 +779,6 @@ VulkanDebugManager::~VulkanDebugManager() for(auto it = m_DiscardStage.begin(); it != m_DiscardStage.end(); it++) it->second.Destroy(); - for(size_t i = 0; i < ARRAY_COUNT(m_DepthMS2ArrayPipe); i++) - m_pDriver->vkDestroyPipeline(dev, m_DepthMS2ArrayPipe[i], NULL); - for(size_t f = 0; f < ARRAY_COUNT(m_DepthArray2MSPipe); f++) for(size_t s = 0; s < ARRAY_COUNT(m_DepthArray2MSPipe[0]); s++) m_pDriver->vkDestroyPipeline(dev, m_DepthArray2MSPipe[f][s], NULL); diff --git a/renderdoc/driver/vulkan/vk_debug.h b/renderdoc/driver/vulkan/vk_debug.h index 1dad03e8e..b1742898a 100644 --- a/renderdoc/driver/vulkan/vk_debug.h +++ b/renderdoc/driver/vulkan/vk_debug.h @@ -63,10 +63,12 @@ public: void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, bytebuf &ret); - void CopyTex2DMSToArray(VkImage destArray, VkImage srcMS, VkExtent3D extent, uint32_t layers, - uint32_t samples, VkFormat fmt); - void CopyArrayToTex2DMS(VkImage destMS, VkImage srcArray, VkExtent3D extent, uint32_t layers, - uint32_t samples, VkFormat fmt); + void CopyTex2DMSToBuffer(VkBuffer destBuffer, VkImage srcMS, VkExtent3D extent, + uint32_t baseSlice, uint32_t numSlices, uint32_t baseSample, + uint32_t numSamples, VkFormat fmt); + + void CopyBufferToTex2DMS(VkImage destMS, VkBuffer srcBuffer, VkExtent3D extent, + uint32_t numSlices, uint32_t numSamples, VkFormat fmt); void FillWithDiscardPattern(VkCommandBuffer cmd, DiscardType type, VkImage image, VkImageLayout curLayout, VkImageSubresourceRange discardRange, @@ -122,23 +124,21 @@ private: // CacheMeshDisplayPipelines std::map m_CachedMeshPipelines; - // CopyArrayToTex2DMS & CopyTex2DMSToArray - VkDescriptorPool m_ArrayMSDescriptorPool; - VkDescriptorSetLayout m_ArrayMSDescSetLayout = VK_NULL_HANDLE; - VkPipelineLayout m_ArrayMSPipeLayout = VK_NULL_HANDLE; + // CopyBufferToTex2DMS + VkDescriptorPool m_BufferMSDescriptorPool; + VkDescriptorSetLayout m_BufferMSDescSetLayout = VK_NULL_HANDLE; + VkPipelineLayout m_BufferMSPipeLayout = VK_NULL_HANDLE; // 8 descriptor sets allows for 4x MSAA with 2 array slices, common for VR targets - VkDescriptorSet m_ArrayMSDescSet[8] = {}; - VkPipeline m_Array2MSPipe = VK_NULL_HANDLE; - VkPipeline m_MS2ArrayPipe = VK_NULL_HANDLE; - VkSampler m_ArrayMSSampler = VK_NULL_HANDLE; + VkDescriptorSet m_BufferMSDescSet[8] = {}; + VkPipeline m_Buffer2MSPipe = VK_NULL_HANDLE; + VkPipeline m_MS2BufferPipe = VK_NULL_HANDLE; + VkPipeline m_DepthMS2BufferPipe = VK_NULL_HANDLE; - // [0] = non-MSAA, [1] = MSAA + // MSAA dummy images VkDeviceMemory m_DummyStencilMemory = VK_NULL_HANDLE; - VkImage m_DummyStencilImage[2] = {VK_NULL_HANDLE}; - VkImageView m_DummyStencilView[2] = {VK_NULL_HANDLE}; + VkImage m_DummyStencilImage = {VK_NULL_HANDLE}; + VkImageView m_DummyStencilView = {VK_NULL_HANDLE}; - // one per depth/stencil output format - VkPipeline m_DepthMS2ArrayPipe[6] = {VK_NULL_HANDLE}; // one per depth/stencil output format, per sample count VkPipeline m_DepthArray2MSPipe[6][4] = {{VK_NULL_HANDLE}}; @@ -159,10 +159,12 @@ private: VkPipeline TexPipeline = VK_NULL_HANDLE; } m_Custom; - void CopyDepthTex2DMSToArray(VkImage destArray, VkImage srcMS, VkExtent3D extent, uint32_t layers, - uint32_t samples, VkFormat fmt); - void CopyDepthArrayToTex2DMS(VkImage destMS, VkImage srcArray, VkExtent3D extent, uint32_t layers, - uint32_t samples, VkFormat fmt); + void CopyDepthTex2DMSToBuffer(VkBuffer destBuffer, VkImage srcMS, VkExtent3D extent, + uint32_t baseSlice, uint32_t numSlices, uint32_t baseSample, + uint32_t numSamples, VkFormat fmt); + + void CopyDepthBufferToTex2DMS(VkImage destMS, VkBuffer srcBuffer, VkExtent3D extent, + uint32_t numSlices, uint32_t numSamples, VkFormat fmt); WrappedVulkan *m_pDriver = NULL; diff --git a/renderdoc/driver/vulkan/vk_initstate.cpp b/renderdoc/driver/vulkan/vk_initstate.cpp index 63f82a581..117fecb6e 100644 --- a/renderdoc/driver/vulkan/vk_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_initstate.cpp @@ -93,6 +93,7 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) WrappedVkImage *im = (WrappedVkImage *)res; const ResourceInfo &resInfo = *im->record->resInfo; const ImageInfo &imageInfo = resInfo.imageInfo; + const bool wasms = imageInfo.sampleCount > 1; LockedImageStateRef state = FindImageState(im->id); @@ -121,57 +122,18 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) bufAlignment = (VkDeviceSize)GetByteSize(1, 1, 1, imageInfo.format, 0); VkBufferCreateInfo bufInfo = { - VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - NULL, - 0, - 0, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, NULL, 0, 0, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, }; - VkImage arrayIm = VK_NULL_HANDLE; - VkImage realim = im->real.As(); int numLayers = imageInfo.layerCount; - if(imageInfo.sampleCount > 1) + if(wasms) { // first decompose to array numLayers *= imageInfo.sampleCount; - - VkImageCreateInfo arrayInfo = { - VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, NULL, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, - VK_IMAGE_TYPE_2D, imageInfo.format, imageInfo.extent, (uint32_t)imageInfo.levelCount, - (uint32_t)numLayers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT, - VK_SHARING_MODE_EXCLUSIVE, 0, NULL, VK_IMAGE_LAYOUT_UNDEFINED, - }; - - if(IsDepthOrStencilFormat(imageInfo.format)) - arrayInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - else - arrayInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT; - - vkr = ObjDisp(d)->CreateImage(Unwrap(d), &arrayInfo, NULL, &arrayIm); - CheckVkResult(vkr); - - GetResourceManager()->WrapResource(Unwrap(d), arrayIm); - - NameUnwrappedVulkanObject( - arrayIm, StringFormat::Fmt("Initial State array image for %s", ToStr(id).c_str())); - - MemoryAllocation arrayMem = - AllocateMemoryForResource(arrayIm, MemoryScope::InitialContents, MemoryType::GPULocal); - - if(arrayMem.mem == VK_NULL_HANDLE) - return false; - - vkr = ObjDisp(d)->BindImageMemory(Unwrap(d), Unwrap(arrayIm), Unwrap(arrayMem.mem), - arrayMem.offs); - CheckVkResult(vkr); - - // we don't use the memory after this, so we don't need to keep a reference. It's needed for - // backing the array image only. } uint32_t planeCount = GetYUVPlaneCount(imageInfo.format); @@ -212,7 +174,8 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) } } - VkFormat sizeFormat = GetDepthOnlyFormat(imageInfo.format); + // keep actual format to size multisampled buffers (the compute path interleaves in-place) + VkFormat sizeFormat = wasms ? imageInfo.format : GetDepthOnlyFormat(imageInfo.format); for(int a = 0; a < numLayers; a++) { @@ -274,59 +237,49 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) ImageBarrierSequence setupBarriers, cleanupBarriers; - VkImageLayout readingLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - if(arrayIm != VK_NULL_HANDLE) - readingLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + const VkImageLayout readingLayout = + wasms ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; state->TempTransition(m_QueueFamilyIdx, readingLayout, VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT, setupBarriers, cleanupBarriers, GetImageTransitionInfo()); InlineSetupImageBarriers(cmd, setupBarriers); m_setupImageBarriers.Merge(setupBarriers); - if(arrayIm != VK_NULL_HANDLE) + if(wasms) { - VkImageMemoryBarrier arrayimBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - 0, - 0, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_GENERAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - Unwrap(arrayIm), - {aspectFlags, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}, - }; - - DoPipelineBarrier(cmd, 1, &arrayimBarrier); - vkr = ObjDisp(d)->EndCommandBuffer(Unwrap(cmd)); CheckVkResult(vkr); - GetDebugManager()->CopyTex2DMSToArray(Unwrap(arrayIm), realim, imageInfo.extent, - imageInfo.layerCount, imageInfo.sampleCount, - imageInfo.format); + GetDebugManager()->CopyTex2DMSToBuffer(Unwrap(dstBuf), realim, imageInfo.extent, 0, + imageInfo.layerCount, 0, imageInfo.sampleCount, + imageInfo.format); cmd = GetNextCmd(); vkr = ObjDisp(d)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); CheckVkResult(vkr); - arrayimBarrier.srcAccessMask = - VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - arrayimBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - arrayimBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; - arrayimBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + VkBufferMemoryBarrier bufBarrier = { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + NULL, + VK_ACCESS_SHADER_WRITE_BIT, + VK_ACCESS_HOST_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + Unwrap(dstBuf), + 0, + bufInfo.size, + }; - DoPipelineBarrier(cmd, 1, &arrayimBarrier); - - realim = Unwrap(arrayIm); + // wait for copy to finish before reading back to host + DoPipelineBarrier(cmd, 1, &bufBarrier); } VkDeviceSize bufOffset = 0; + const int numLayersToCopy = wasms ? 0 : numLayers; // loop over every slice/mip, copying it to the appropriate point in the buffer - for(int a = 0; a < numLayers; a++) + for(int a = 0; a < numLayersToCopy; a++) { VkExtent3D extent = imageInfo.extent; @@ -425,12 +378,6 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) ObjDisp(d)->DestroyBuffer(Unwrap(d), Unwrap(dstBuf), NULL); GetResourceManager()->ReleaseWrappedResource(dstBuf); - if(arrayIm != VK_NULL_HANDLE) - { - ObjDisp(d)->DestroyImage(Unwrap(d), Unwrap(arrayIm), NULL); - GetResourceManager()->ReleaseWrappedResource(arrayIm); - } - VkInitialContents initialContents(type, readbackmem); // include the sparse page table if it exists @@ -1479,12 +1426,8 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, V { // create a buffer with memory attached, which we will fill with the initial contents VkBufferCreateInfo bufInfo = { - VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - NULL, - 0, - ContentsSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - }; + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, NULL, 0, ContentsSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT}; vkr = vkCreateBuffer(d, &bufInfo, NULL, &uploadBuf); CheckVkResult(vkr); @@ -1585,43 +1528,26 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, V } else { - // MSAA textures we upload into an array image, then the apply does an array-to-MSAA copy - // instead of the usual buffer-to-image copies. - uint32_t numLayers = c.arrayLayers * (uint32_t)c.samples; + // use a GPU-local buffer for the MSAA SSBO for read speeds on non-mobile HW. + VkBuffer gpuBuf = VK_NULL_HANDLE; - VkImageCreateInfo arrayInfo = { - VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - NULL, - VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, - VK_IMAGE_TYPE_2D, - c.format, - c.extent, - c.mipLevels, - numLayers, - VK_SAMPLE_COUNT_1_BIT, - VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - VK_SHARING_MODE_EXCLUSIVE, - 0, - NULL, - VK_IMAGE_LAYOUT_UNDEFINED, + // create a buffer with memory attached, which we will fill with the initial contents + VkBufferCreateInfo gpuBufInfo = { + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, NULL, 0, ContentsSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, }; - VkImage arrayIm; - - vkr = vkCreateImage(d, &arrayInfo, NULL, &arrayIm); + vkr = vkCreateBuffer(d, &gpuBufInfo, NULL, &gpuBuf); CheckVkResult(vkr); - NameVulkanObject( - arrayIm, StringFormat::Fmt("Initial State array image for %s", ToStr(id).c_str())); + MemoryAllocation gpuUploadMemory = + AllocateMemoryForResource(gpuBuf, MemoryScope::InitialContents, MemoryType::GPULocal); - MemoryAllocation arrayMem = - AllocateMemoryForResource(arrayIm, MemoryScope::InitialContents, MemoryType::GPULocal); - - if(arrayMem.mem == VK_NULL_HANDLE) + if(gpuUploadMemory.mem == VK_NULL_HANDLE) return false; - vkr = vkBindImageMemory(d, arrayIm, arrayMem.mem, arrayMem.offs); + vkr = vkBindBufferMemory(d, gpuBuf, gpuUploadMemory.mem, gpuUploadMemory.offs); CheckVkResult(vkr); VkCommandBuffer cmd = GetNextCmd(); @@ -1635,110 +1561,26 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, V vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); CheckVkResult(vkr); - VkExtent3D extent = c.extent; + VkBufferCopy bufCopy = {0, 0, ContentsSize}; + ObjDisp(cmd)->CmdCopyBuffer(Unwrap(cmd), Unwrap(uploadBuf), Unwrap(gpuBuf), 1, &bufCopy); - VkFormat fmt = c.format; - VkImageAspectFlags aspectFlags = FormatImageAspects(fmt); - - VkImageMemoryBarrier dstimBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + // wait for copy + VkBufferMemoryBarrier bufBarrier = { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, NULL, - 0, - 0, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, - Unwrap(arrayIm), - {aspectFlags, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}}; - - DoPipelineBarrier(cmd, 1, &dstimBarrier); - - VkDeviceSize bufOffset = 0; - - // must ensure offset remains valid. Must be multiple of block size, or 4, depending on - // format - VkDeviceSize bufAlignment = 4; - if(IsBlockFormat(fmt)) - bufAlignment = (VkDeviceSize)GetByteSize(1, 1, 1, fmt, 0); - - rdcarray mainCopies, stencilCopies; - - // copy each slice/mip individually - for(uint32_t a = 0; a < numLayers; a++) - { - extent = c.extent; - - for(uint32_t m = 0; m < c.mipLevels; m++) - { - VkBufferImageCopy region = { - 0, - 0, - 0, - {aspectFlags, m, a, 1}, - { - 0, 0, 0, - }, - extent, - }; - - bufOffset = AlignUp(bufOffset, bufAlignment); - - region.bufferOffset = bufOffset; - - // for depth/stencil copies, copy depth first - if(aspectFlags == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - - VkFormat sizeFormat = GetDepthOnlyFormat(fmt); - - // pass 0 for mip since we've already pre-downscaled extent - bufOffset += GetByteSize(extent.width, extent.height, extent.depth, sizeFormat, 0); - - mainCopies.push_back(region); - - if(aspectFlags == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) - { - // if it's a depth/stencil format, copy stencil now - bufOffset = AlignUp(bufOffset, bufAlignment); - - region.bufferOffset = bufOffset; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - - bufOffset += - GetByteSize(extent.width, extent.height, extent.depth, VK_FORMAT_S8_UINT, 0); - - stencilCopies.push_back(region); - } - - // update the extent for the next mip - extent.width = RDCMAX(extent.width >> 1, 1U); - extent.height = RDCMAX(extent.height >> 1, 1U); - extent.depth = RDCMAX(extent.depth >> 1, 1U); - } - } - - ObjDisp(cmd)->CmdCopyBufferToImage(Unwrap(cmd), Unwrap(uploadBuf), Unwrap(arrayIm), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - (uint32_t)mainCopies.size(), &mainCopies[0]); - - if(!stencilCopies.empty()) - ObjDisp(cmd)->CmdCopyBufferToImage(Unwrap(cmd), Unwrap(uploadBuf), Unwrap(arrayIm), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - (uint32_t)stencilCopies.size(), &stencilCopies[0]); - - // once transfers complete, get ready for copy array->ms - dstimBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - dstimBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - dstimBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - dstimBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - DoPipelineBarrier(cmd, 1, &dstimBarrier); + Unwrap(gpuBuf), + 0, + VK_WHOLE_SIZE, + }; + DoPipelineBarrier(cmd, 1, &bufBarrier); vkr = ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); CheckVkResult(vkr); - // INITSTATEBATCH SubmitCmds(); FlushQ(); @@ -1746,9 +1588,8 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, V vkDestroyBuffer(d, uploadBuf, NULL); FreeMemoryAllocation(uploadMemory); - initialContents.buf = VK_NULL_HANDLE; - initialContents.img = arrayIm; - initialContents.mem = arrayMem; + initialContents.buf = gpuBuf; + initialContents.mem = gpuUploadMemory; } GetResourceManager()->SetInitialContents(id, initialContents); @@ -2082,13 +1923,13 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten InlineSetupImageBarriers(cmd, setupBarriers); m_setupImageBarriers.Merge(setupBarriers); - VkImage arrayIm = initial.img; + VkBuffer buf = initial.buf; vkr = ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); CheckVkResult(vkr); - GetDebugManager()->CopyArrayToTex2DMS(ToUnwrappedHandle(live), Unwrap(arrayIm), - c.extent, c.arrayLayers, (uint32_t)c.samples, fmt); + GetDebugManager()->CopyBufferToTex2DMS(ToUnwrappedHandle(live), Unwrap(buf), + c.extent, c.arrayLayers, (uint32_t)c.samples, fmt); #if ENABLED(SINGLE_FLUSH_VALIDATE) SubmitAndFlushImageStateBarriers(m_setupImageBarriers); diff --git a/renderdoc/driver/vulkan/vk_manager.h b/renderdoc/driver/vulkan/vk_manager.h index da20f62a7..872428e73 100644 --- a/renderdoc/driver/vulkan/vk_manager.h +++ b/renderdoc/driver/vulkan/vk_manager.h @@ -107,7 +107,6 @@ struct VkInitialContents FreeAlignedBuffer(inlineData); rm->ResourceTypeRelease(GetWrapped(buf)); - rm->ResourceTypeRelease(GetWrapped(img)); SAFE_DELETE(sparseTables); SAFE_DELETE(sparseBind); @@ -127,7 +126,6 @@ struct VkInitialContents // for plain resources, we store the resource type and memory allocation details of the contents VkResourceType type; VkBuffer buf; - VkImage img; MemoryAllocation mem; Tag tag; @@ -425,7 +423,6 @@ public: void FixupStorageBufferMemory(const std::unordered_set &storageBuffers); void ClearReferencedMemory(); MemRefs *FindMemRefs(ResourceId mem); - ImgRefs *FindImgRefs(ResourceId img); inline InitPolicy GetInitPolicy() { return m_InitPolicy; } void SetOptimisationLevel(ReplayOptimisationLevel level) diff --git a/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp b/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp deleted file mode 100644 index 7dc40929e..000000000 --- a/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp +++ /dev/null @@ -1,808 +0,0 @@ -/****************************************************************************** - * The MIT License (MIT) - * - * Copyright (c) 2019-2022 Baldur Karlsson - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - ******************************************************************************/ - -#include "maths/matrix.h" -#include "vk_core.h" -#include "vk_debug.h" - -#define VULKAN 1 -#include "data/glsl/glsl_ubos_cpp.h" - -void VulkanDebugManager::CopyTex2DMSToArray(VkImage destArray, VkImage srcMS, VkExtent3D extent, - uint32_t layers, uint32_t samples, VkFormat fmt) -{ - if(!m_pDriver->GetDeviceEnabledFeatures().shaderStorageImageWriteWithoutFormat) - return; - - if(m_MS2ArrayPipe == VK_NULL_HANDLE) - return; - - if(IsDepthOrStencilFormat(fmt)) - { - CopyDepthTex2DMSToArray(destArray, srcMS, extent, layers, samples, fmt); - return; - } - - VkDevice dev = m_Device; - - VkResult vkr = VK_SUCCESS; - - VkImageView srcView, destView; - - VkImageViewCreateInfo viewInfo = { - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - NULL, - 0, - srcMS, - VK_IMAGE_VIEW_TYPE_2D_ARRAY, - VK_FORMAT_UNDEFINED, - {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY}, - { - VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS, - }, - }; - - uint32_t bs = GetByteSize(1, 1, 1, fmt, 0); - - if(bs == 1) - viewInfo.format = VK_FORMAT_R8_UINT; - else if(bs == 2) - viewInfo.format = VK_FORMAT_R16_UINT; - else if(bs == 4) - viewInfo.format = VK_FORMAT_R32_UINT; - else if(bs == 8) - viewInfo.format = VK_FORMAT_R32G32_UINT; - else if(bs == 16) - viewInfo.format = VK_FORMAT_R32G32B32A32_UINT; - - if(viewInfo.format == VK_FORMAT_UNDEFINED) - { - RDCERR("Can't copy 2D to Array with format %s", ToStr(fmt).c_str()); - return; - } - - VkMarkerRegion region("CopyTex2DMSToArray"); - - if(IsStencilOnlyFormat(fmt)) - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - else if(IsDepthOrStencilFormat(fmt)) - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - - vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &srcView); - CheckVkResult(vkr); - NameUnwrappedVulkanObject(srcView, "MS -> Array srcView"); - - viewInfo.image = destArray; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; - - const uint32_t batchSize = ARRAY_COUNT(m_ArrayMSDescSet); - - rdcarray views; - - VkCommandBuffer cmd = VK_NULL_HANDLE; - - VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; - - for(uint32_t slice = 0; slice < layers * samples; slice++) - { - // if we don't have a current cmd buffer, start a new one - if(cmd == VK_NULL_HANDLE) - { - cmd = m_pDriver->GetNextCmd(); - - if(cmd == VK_NULL_HANDLE) - return; - - ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - - ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, - Unwrap(m_MS2ArrayPipe)); - } - - uint32_t batchIndex = slice % batchSize; - - viewInfo.subresourceRange.baseArrayLayer = slice; - viewInfo.subresourceRange.layerCount = 1; - - vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &destView); - CheckVkResult(vkr); - NameUnwrappedVulkanObject(destView, "MS -> Array destView"); - - views.push_back(destView); - - VkDescriptorImageInfo srcdesc = {0}; - srcdesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - srcdesc.imageView = srcView; - srcdesc.sampler = Unwrap(m_ArrayMSSampler); // not used - we use texelFetch - - VkDescriptorImageInfo destdesc = {0}; - destdesc.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - destdesc.imageView = destView; - - VkWriteDescriptorSet writeSet[] = { - {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet[batchIndex]), 0, 0, - 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc, NULL, NULL}, - {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet[batchIndex]), 2, 0, - 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &destdesc, NULL, NULL}, - }; - - ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), ARRAY_COUNT(writeSet), writeSet, 0, NULL); - - ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, - Unwrap(m_ArrayMSPipeLayout), 0, 1, - UnwrapPtr(m_ArrayMSDescSet[batchIndex]), 0, NULL); - - Vec4u params = {samples, slice / samples, slice % samples, 0}; - - ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_ArrayMSPipeLayout), VK_SHADER_STAGE_ALL, 0, - sizeof(Vec4u), ¶ms); - - ObjDisp(cmd)->CmdDispatch(Unwrap(cmd), extent.width, extent.height, 1); - - // if we're about to end a batch, or we're done entirely, submit and flush - if(batchIndex == batchSize - 1 || slice == layers * samples - 1) - { - ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); - - cmd = VK_NULL_HANDLE; - - // submit cmds and wait for idle so we can readback - m_pDriver->SubmitCmds(); - m_pDriver->FlushQ(); - } - } - - RDCASSERT(cmd == VK_NULL_HANDLE); - - for(VkImageView view : views) - ObjDisp(dev)->DestroyImageView(Unwrap(dev), view, NULL); - - ObjDisp(dev)->DestroyImageView(Unwrap(dev), srcView, NULL); -} - -void VulkanDebugManager::CopyDepthTex2DMSToArray(VkImage destArray, VkImage srcMS, VkExtent3D extent, - uint32_t layers, uint32_t samples, VkFormat fmt) -{ - VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; - - int pipeIndex = 0; - switch(fmt) - { - case VK_FORMAT_D16_UNORM: pipeIndex = 0; break; - case VK_FORMAT_D16_UNORM_S8_UINT: - pipeIndex = 1; - aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - break; - case VK_FORMAT_X8_D24_UNORM_PACK32: pipeIndex = 2; break; - case VK_FORMAT_D24_UNORM_S8_UINT: - pipeIndex = 3; - aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - break; - case VK_FORMAT_D32_SFLOAT: pipeIndex = 4; break; - case VK_FORMAT_D32_SFLOAT_S8_UINT: - pipeIndex = 5; - aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - break; - default: RDCERR("Unexpected depth format: %d", fmt); return; - } - - VkPipeline pipe = m_DepthMS2ArrayPipe[pipeIndex]; - - if(pipe == VK_NULL_HANDLE) - return; - - VkMarkerRegion region("CopyDepthTex2DMSToArray"); - - VkDevice dev = m_Device; - - VkResult vkr = VK_SUCCESS; - - VkImageView srcDepthView = VK_NULL_HANDLE, srcStencilView = VK_NULL_HANDLE; - VkImageView *destView = new VkImageView[layers * samples]; - - VkImageViewCreateInfo viewInfo = { - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - NULL, - 0, - srcMS, - VK_IMAGE_VIEW_TYPE_2D_ARRAY, - fmt, - {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO}, - { - VK_IMAGE_ASPECT_DEPTH_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS, - }, - }; - - vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &srcDepthView); - CheckVkResult(vkr); - NameUnwrappedVulkanObject(srcDepthView, "Depth MS -> Array srcDepthView"); - - if(aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) - { - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &srcStencilView); - CheckVkResult(vkr); - NameUnwrappedVulkanObject(srcStencilView, "Depth MS -> Array srcStencilView"); - } - - viewInfo.subresourceRange.aspectMask = aspectFlags; - viewInfo.image = destArray; - - viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - - for(uint32_t i = 0; i < layers * samples; i++) - { - viewInfo.subresourceRange.baseArrayLayer = i; - viewInfo.subresourceRange.layerCount = 1; - - vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &destView[i]); - CheckVkResult(vkr); - NameUnwrappedVulkanObject(destView[i], "Depth MS -> Array destView[i]"); - } - - VkDescriptorImageInfo srcdesc[2]; - srcdesc[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - srcdesc[0].imageView = srcDepthView; - srcdesc[0].sampler = Unwrap(m_ArrayMSSampler); // not used - we use texelFetch - srcdesc[1].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - srcdesc[1].imageView = srcStencilView; - srcdesc[1].sampler = Unwrap(m_ArrayMSSampler); // not used - we use texelFetch - - if((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) == 0) - { - if(m_DummyStencilView[1] != VK_NULL_HANDLE) - { - srcdesc[1].imageView = Unwrap(m_DummyStencilView[1]); - } - else - { - // as a last fallback, hope that setting an incompatible view (float not int) will not break - // too badly. This only gets hit when the implementation has such poor format support that - // there are no uint formats that can be sampled as MSAA. - srcdesc[1].imageView = srcDepthView; - } - } - - VkWriteDescriptorSet writeSet[] = { - {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet[0]), 0, 0, 1, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc[0], NULL, NULL}, - {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet[0]), 1, 0, 1, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc[1], NULL, NULL}, - }; - - ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), 2, writeSet, 0, NULL); - - // create a bespoke framebuffer and renderpass for rendering - VkAttachmentDescription attDesc = {0, - fmt, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_CLEAR, - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_CLEAR, - VK_ATTACHMENT_STORE_OP_STORE, - VK_IMAGE_LAYOUT_GENERAL, - VK_IMAGE_LAYOUT_GENERAL}; - - VkAttachmentReference attRef = {0, VK_IMAGE_LAYOUT_GENERAL}; - - VkSubpassDescription sub = {}; - sub.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - sub.pDepthStencilAttachment = &attRef; - - VkRenderPassCreateInfo rpinfo = { - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - NULL, - 0, - 1, - &attDesc, - 1, - &sub, - 0, - NULL, // dependencies - }; - - VkRenderPass rp = VK_NULL_HANDLE; - - ObjDisp(dev)->CreateRenderPass(Unwrap(dev), &rpinfo, NULL, &rp); - - VkFramebufferCreateInfo fbinfo = { - VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - NULL, - 0, - rp, - 1, - NULL, - extent.width, - extent.height, - 1, - }; - - VkFramebuffer *fb = new VkFramebuffer[layers * samples]; - - for(uint32_t i = 0; i < layers * samples; i++) - { - fbinfo.pAttachments = destView + i; - - vkr = ObjDisp(dev)->CreateFramebuffer(Unwrap(dev), &fbinfo, NULL, &fb[i]); - CheckVkResult(vkr); - } - - VkCommandBuffer cmd = m_pDriver->GetNextCmd(); - - if(cmd == VK_NULL_HANDLE) - return; - - VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; - - ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - - VkClearValue clearval = {}; - - VkRenderPassBeginInfo rpbegin = { - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, NULL, rp, VK_NULL_HANDLE, - {{0, 0}, {extent.width, extent.height}}, 1, &clearval, - }; - - uint32_t numStencil = 1; - - if(aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) - numStencil = 256; - - Vec4u params; - params.x = samples; - - for(uint32_t i = 0; i < layers * samples; i++) - { - rpbegin.framebuffer = fb[i]; - - ObjDisp(cmd)->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); - - ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(pipe)); - ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(m_ArrayMSPipeLayout), 0, 1, - UnwrapPtr(m_ArrayMSDescSet[0]), 0, NULL); - - VkViewport viewport = {0.0f, 0.0f, (float)extent.width, (float)extent.height, 0.0f, 1.0f}; - ObjDisp(cmd)->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); - - params.y = i % samples; // currentSample; - params.z = i / samples; // currentSlice; - - for(uint32_t s = 0; s < numStencil; s++) - { - params.w = numStencil == 1 ? 1000 : s; // currentStencil; - - ObjDisp(cmd)->CmdSetStencilReference(Unwrap(cmd), VK_STENCIL_FACE_FRONT_AND_BACK, s); - ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_ArrayMSPipeLayout), VK_SHADER_STAGE_ALL, - 0, sizeof(Vec4u), ¶ms); - ObjDisp(cmd)->CmdDraw(Unwrap(cmd), 4, 1, 0, 0); - } - - ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd)); - } - - ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); - - // submit cmds and wait for idle so we can readback - m_pDriver->SubmitCmds(); - m_pDriver->FlushQ(); - - for(uint32_t i = 0; i < layers * samples; i++) - ObjDisp(dev)->DestroyFramebuffer(Unwrap(dev), fb[i], NULL); - ObjDisp(dev)->DestroyRenderPass(Unwrap(dev), rp, NULL); - - ObjDisp(dev)->DestroyImageView(Unwrap(dev), srcDepthView, NULL); - if(srcStencilView != VK_NULL_HANDLE) - ObjDisp(dev)->DestroyImageView(Unwrap(dev), srcStencilView, NULL); - for(uint32_t i = 0; i < layers * samples; i++) - ObjDisp(dev)->DestroyImageView(Unwrap(dev), destView[i], NULL); - - SAFE_DELETE_ARRAY(destView); - SAFE_DELETE_ARRAY(fb); -} - -void VulkanDebugManager::CopyArrayToTex2DMS(VkImage destMS, VkImage srcArray, VkExtent3D extent, - uint32_t layers, uint32_t samples, VkFormat fmt) -{ - if(!m_pDriver->GetDeviceEnabledFeatures().shaderStorageImageMultisample || - !m_pDriver->GetDeviceEnabledFeatures().shaderStorageImageWriteWithoutFormat) - return; - - if(m_Array2MSPipe == VK_NULL_HANDLE) - return; - - if(IsDepthOrStencilFormat(fmt)) - { - CopyDepthArrayToTex2DMS(destMS, srcArray, extent, layers, samples, fmt); - return; - } - - VkDevice dev = m_Device; - - VkResult vkr = VK_SUCCESS; - - VkImageView srcView, destView; - - VkImageViewCreateInfo viewInfo = { - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - NULL, - 0, - srcArray, - VK_IMAGE_VIEW_TYPE_2D_ARRAY, - VK_FORMAT_UNDEFINED, - {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY}, - { - VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS, - }, - }; - - uint32_t bs = GetByteSize(1, 1, 1, fmt, 0); - - if(bs == 1) - viewInfo.format = VK_FORMAT_R8_UINT; - else if(bs == 2) - viewInfo.format = VK_FORMAT_R16_UINT; - else if(bs == 4) - viewInfo.format = VK_FORMAT_R32_UINT; - else if(bs == 8) - viewInfo.format = VK_FORMAT_R32G32_UINT; - else if(bs == 16) - viewInfo.format = VK_FORMAT_R32G32B32A32_UINT; - - if(viewInfo.format == VK_FORMAT_UNDEFINED) - { - RDCERR("Can't copy Array to MS with format %s", ToStr(fmt).c_str()); - return; - } - - VkMarkerRegion region("CopyArrayToTex2DMS"); - - if(IsStencilOnlyFormat(fmt)) - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - else if(IsDepthOrStencilFormat(fmt)) - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - - vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &srcView); - CheckVkResult(vkr); - NameUnwrappedVulkanObject(srcView, "Array -> MS srcView"); - - viewInfo.image = destMS; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; - - vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &destView); - CheckVkResult(vkr); - NameUnwrappedVulkanObject(destView, "Array -> MS destView"); - - VkDescriptorImageInfo srcdesc = {0}; - srcdesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - srcdesc.imageView = srcView; - srcdesc.sampler = Unwrap(m_ArrayMSSampler); // not used - we use texelFetch - - VkDescriptorImageInfo destdesc = {0}; - destdesc.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - destdesc.imageView = destView; - - VkWriteDescriptorSet writeSet[] = { - {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet[0]), 0, 0, 1, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc, NULL, NULL}, - {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet[0]), 2, 0, 1, - VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &destdesc, NULL, NULL}, - }; - - ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), ARRAY_COUNT(writeSet), writeSet, 0, NULL); - - VkCommandBuffer cmd = m_pDriver->GetNextCmd(); - - if(cmd == VK_NULL_HANDLE) - return; - - VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; - - ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - - ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, Unwrap(m_Array2MSPipe)); - ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, - Unwrap(m_ArrayMSPipeLayout), 0, 1, - UnwrapPtr(m_ArrayMSDescSet[0]), 0, NULL); - - Vec4u params = {samples, 0, 0, 0}; - - ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_ArrayMSPipeLayout), VK_SHADER_STAGE_ALL, 0, - sizeof(Vec4u), ¶ms); - - ObjDisp(cmd)->CmdDispatch(Unwrap(cmd), extent.width, extent.height, layers * samples); - - ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); - - // submit cmds and wait for idle so we can readback - m_pDriver->SubmitCmds(); - m_pDriver->FlushQ(); - - ObjDisp(dev)->DestroyImageView(Unwrap(dev), srcView, NULL); - ObjDisp(dev)->DestroyImageView(Unwrap(dev), destView, NULL); -} - -void VulkanDebugManager::CopyDepthArrayToTex2DMS(VkImage destMS, VkImage srcArray, VkExtent3D extent, - uint32_t layers, uint32_t samples, VkFormat fmt) -{ - VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; - - int pipeIndex = 0; - switch(fmt) - { - case VK_FORMAT_D16_UNORM: pipeIndex = 0; break; - case VK_FORMAT_D16_UNORM_S8_UINT: - pipeIndex = 1; - aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - break; - case VK_FORMAT_X8_D24_UNORM_PACK32: pipeIndex = 2; break; - case VK_FORMAT_D24_UNORM_S8_UINT: - pipeIndex = 3; - aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - break; - case VK_FORMAT_D32_SFLOAT: pipeIndex = 4; break; - case VK_FORMAT_D32_SFLOAT_S8_UINT: - pipeIndex = 5; - aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - break; - default: RDCERR("Unexpected depth format: %d", fmt); return; - } - - // 0-based from 2x MSAA - uint32_t sampleIndex = SampleIndex((VkSampleCountFlagBits)samples) - 1; - - if(sampleIndex >= ARRAY_COUNT(m_DepthArray2MSPipe[0])) - { - RDCERR("Unsupported sample count %u", samples); - return; - } - - VkPipeline pipe = m_DepthArray2MSPipe[pipeIndex][sampleIndex]; - - if(pipe == VK_NULL_HANDLE) - return; - - VkMarkerRegion region("CopyDepthArrayToTex2DMS"); - - VkDevice dev = m_Device; - - VkResult vkr = VK_SUCCESS; - - VkImageView srcDepthView = VK_NULL_HANDLE, srcStencilView = VK_NULL_HANDLE; - VkImageView *destView = new VkImageView[layers]; - - VkImageViewCreateInfo viewInfo = { - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - NULL, - 0, - srcArray, - VK_IMAGE_VIEW_TYPE_2D_ARRAY, - fmt, - {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO}, - { - VK_IMAGE_ASPECT_DEPTH_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS, - }, - }; - - vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &srcDepthView); - CheckVkResult(vkr); - NameUnwrappedVulkanObject(srcDepthView, "Depth Array -> MS srcDepthView"); - - if(aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) - { - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &srcStencilView); - CheckVkResult(vkr); - NameUnwrappedVulkanObject(srcStencilView, "Depth Array -> MS srcStencilView"); - } - - viewInfo.subresourceRange.aspectMask = aspectFlags; - viewInfo.image = destMS; - - viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - - for(uint32_t i = 0; i < layers; i++) - { - viewInfo.subresourceRange.baseArrayLayer = i; - viewInfo.subresourceRange.layerCount = 1; - - vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &destView[i]); - CheckVkResult(vkr); - NameUnwrappedVulkanObject(destView[i], "Depth Array -> MS destView[i]"); - } - - VkDescriptorImageInfo srcdesc[2]; - srcdesc[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - srcdesc[0].imageView = srcDepthView; - srcdesc[0].sampler = Unwrap(m_ArrayMSSampler); // not used - we use texelFetch - srcdesc[1].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - srcdesc[1].imageView = srcStencilView; - srcdesc[1].sampler = Unwrap(m_ArrayMSSampler); // not used - we use texelFetch - - if((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) == 0) - { - if(m_DummyStencilView[0] != VK_NULL_HANDLE) - { - srcdesc[1].imageView = Unwrap(m_DummyStencilView[0]); - } - else - { - // as a last fallback, hope that setting an incompatible view (float not int) will not break - // too badly. This only gets hit when the implementation has such poor format support that - // there are no uint formats that can be sampled as MSAA. - srcdesc[1].imageView = srcDepthView; - } - } - - VkWriteDescriptorSet writeSet[] = { - {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet[0]), 0, 0, 1, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc[0], NULL, NULL}, - {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet[0]), 1, 0, 1, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc[1], NULL, NULL}, - }; - - ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), 2, writeSet, 0, NULL); - - // create a bespoke framebuffer and renderpass for rendering - VkAttachmentDescription attDesc = {0, - fmt, - (VkSampleCountFlagBits)samples, - VK_ATTACHMENT_LOAD_OP_CLEAR, - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_CLEAR, - VK_ATTACHMENT_STORE_OP_STORE, - VK_IMAGE_LAYOUT_GENERAL, - VK_IMAGE_LAYOUT_GENERAL}; - - VkAttachmentReference attRef = {0, VK_IMAGE_LAYOUT_GENERAL}; - - VkSubpassDescription sub = {}; - sub.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - sub.pDepthStencilAttachment = &attRef; - - VkRenderPassCreateInfo rpinfo = { - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - NULL, - 0, - 1, - &attDesc, - 1, - &sub, - 0, - NULL, // dependencies - }; - - VkRenderPass rp = VK_NULL_HANDLE; - - ObjDisp(dev)->CreateRenderPass(Unwrap(dev), &rpinfo, NULL, &rp); - - VkFramebufferCreateInfo fbinfo = { - VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - NULL, - 0, - rp, - 1, - NULL, - extent.width, - extent.height, - 1, - }; - - VkFramebuffer *fb = new VkFramebuffer[layers]; - - for(uint32_t i = 0; i < layers; i++) - { - fbinfo.pAttachments = destView + i; - - vkr = ObjDisp(dev)->CreateFramebuffer(Unwrap(dev), &fbinfo, NULL, &fb[i]); - CheckVkResult(vkr); - } - - VkCommandBuffer cmd = m_pDriver->GetNextCmd(); - - if(cmd == VK_NULL_HANDLE) - return; - - VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; - - ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - - VkClearValue clearval = {}; - - VkRenderPassBeginInfo rpbegin = { - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, NULL, rp, VK_NULL_HANDLE, - {{0, 0}, {extent.width, extent.height}}, 1, &clearval, - }; - - uint32_t numStencil = 1; - - if(aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) - numStencil = 256; - - Vec4u params; - params.x = samples; - params.y = 0; // currentSample; - - for(uint32_t i = 0; i < layers; i++) - { - rpbegin.framebuffer = fb[i]; - - ObjDisp(cmd)->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); - - ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(pipe)); - ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(m_ArrayMSPipeLayout), 0, 1, - UnwrapPtr(m_ArrayMSDescSet[0]), 0, NULL); - - VkViewport viewport = {0.0f, 0.0f, (float)extent.width, (float)extent.height, 0.0f, 1.0f}; - ObjDisp(cmd)->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); - - params.z = i; // currentSlice; - - for(uint32_t s = 0; s < numStencil; s++) - { - params.w = numStencil == 1 ? 1000 : s; // currentStencil; - - ObjDisp(cmd)->CmdSetStencilReference(Unwrap(cmd), VK_STENCIL_FACE_FRONT_AND_BACK, s); - ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_ArrayMSPipeLayout), VK_SHADER_STAGE_ALL, - 0, sizeof(Vec4u), ¶ms); - ObjDisp(cmd)->CmdDraw(Unwrap(cmd), 4, 1, 0, 0); - } - - ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd)); - } - - ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); - - // submit cmds and wait for idle so we can readback - m_pDriver->SubmitCmds(); - m_pDriver->FlushQ(); - - for(uint32_t i = 0; i < layers; i++) - ObjDisp(dev)->DestroyFramebuffer(Unwrap(dev), fb[i], NULL); - ObjDisp(dev)->DestroyRenderPass(Unwrap(dev), rp, NULL); - - ObjDisp(dev)->DestroyImageView(Unwrap(dev), srcDepthView, NULL); - if(srcStencilView != VK_NULL_HANDLE) - ObjDisp(dev)->DestroyImageView(Unwrap(dev), srcStencilView, NULL); - for(uint32_t i = 0; i < layers; i++) - ObjDisp(dev)->DestroyImageView(Unwrap(dev), destView[i], NULL); - - SAFE_DELETE_ARRAY(destView); - SAFE_DELETE_ARRAY(fb); -} diff --git a/renderdoc/driver/vulkan/vk_msaa_buffer_conv.cpp b/renderdoc/driver/vulkan/vk_msaa_buffer_conv.cpp new file mode 100644 index 000000000..f50f854ee --- /dev/null +++ b/renderdoc/driver/vulkan/vk_msaa_buffer_conv.cpp @@ -0,0 +1,729 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "maths/matrix.h" +#include "vk_core.h" +#include "vk_debug.h" + +#define VULKAN 1 +#include "data/glsl/glsl_globals.h" +#include "data/glsl/glsl_ubos_cpp.h" + +void VulkanDebugManager::CopyTex2DMSToBuffer(VkBuffer destBuffer, VkImage srcMS, VkExtent3D extent, + uint32_t baseSlice, uint32_t numSlices, + uint32_t baseSample, uint32_t numSamples, VkFormat fmt) +{ + if(IsDepthOrStencilFormat(fmt)) + { + CopyDepthTex2DMSToBuffer(destBuffer, srcMS, extent, baseSlice, numSlices, baseSample, + numSamples, fmt); + return; + } + + if(m_MS2BufferPipe == VK_NULL_HANDLE) + return; + + VkDevice dev = m_Device; + + VkResult vkr = VK_SUCCESS; + + VkImageView srcView; + + VkImageViewCreateInfo viewInfo = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + NULL, + 0, + srcMS, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + VK_FORMAT_UNDEFINED, + {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY}, + { + VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS, + }, + }; + + uint32_t bs = GetByteSize(1, 1, 1, fmt, 0); + + if(bs == 1) + viewInfo.format = VK_FORMAT_R8_UINT; + else if(bs == 2) + viewInfo.format = VK_FORMAT_R16_UINT; + else if(bs == 4) + viewInfo.format = VK_FORMAT_R32_UINT; + else if(bs == 8) + viewInfo.format = VK_FORMAT_R32G32_UINT; + else if(bs == 16) + viewInfo.format = VK_FORMAT_R32G32B32A32_UINT; + + if(viewInfo.format == VK_FORMAT_UNDEFINED) + { + RDCERR("Can't copy 2D to Buffer with format %s", ToStr(fmt).c_str()); + return; + } + + VkMarkerRegion region("CopyTex2DMSToBuffer"); + + vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &srcView); + CheckVkResult(vkr); + NameUnwrappedVulkanObject(srcView, "MS -> Buffer srcView"); + + VkCommandBuffer cmd = VK_NULL_HANDLE; + VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; + + const uint32_t dispatchBufferSize = GetByteSize(extent.width, extent.height, extent.depth, fmt, 0); + const uint32_t descriptorBatchSize = ARRAY_COUNT(m_BufferMSDescSet); + + VkDescriptorImageInfo srcdesc = {0}; + srcdesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + srcdesc.imageView = srcView; + srcdesc.sampler = VK_NULL_HANDLE; // not used - we use texelFetch + + VkDescriptorBufferInfo destdesc = {0}; + destdesc.buffer = destBuffer; + destdesc.offset = 0; + destdesc.range = dispatchBufferSize; + + uint32_t currentBatch = 0; + + for(uint32_t currentSlice = baseSlice; currentSlice < numSlices + baseSlice; currentSlice++) + { + for(uint32_t currentSample = baseSample; currentSample < numSamples + baseSample; currentSample++) + { + // if we don't have a current cmd buffer, start a new one + if(cmd == VK_NULL_HANDLE) + { + cmd = m_pDriver->GetNextCmd(); + + if(cmd == VK_NULL_HANDLE) + return; + + ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + + ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, + Unwrap(m_MS2BufferPipe)); + } + + const uint32_t batchIndex = currentBatch % descriptorBatchSize; + VkWriteDescriptorSet writeSet[] = { + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_BufferMSDescSet[batchIndex]), 0, + 0, 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &srcdesc, NULL, NULL}, + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_BufferMSDescSet[batchIndex]), 2, + 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, NULL, &destdesc, NULL}, + }; + + // if the byte size is less than 4, we need to multisample. + const uint32_t msDivider = bs < 4 ? (4 / bs) : 1; + const uint32_t workGroupDivider = MS_DISPATCH_LOCAL_SIZE * msDivider; + const uint32_t numWorkGroup = + AlignUp(extent.width * extent.height, workGroupDivider) / workGroupDivider; + const uint32_t maxInvoc = AlignUp(extent.width * extent.height, msDivider) / msDivider; + + Vec4u params[2] = { + {extent.width, currentSlice, currentSample, bs}, {maxInvoc, 0, 0, 0}, + }; + + ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), ARRAY_COUNT(writeSet), writeSet, 0, NULL); + + ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, + Unwrap(m_BufferMSPipeLayout), 0, 1, + UnwrapPtr(m_BufferMSDescSet[batchIndex]), 0, NULL); + ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_BufferMSPipeLayout), VK_SHADER_STAGE_ALL, + 0, sizeof(Vec4u) * 2, ¶ms); + + // Use a 1D workgroup size so that we don't have to worry about width or height + // being a multiple of our multisample size + ObjDisp(cmd)->CmdDispatch(Unwrap(cmd), numWorkGroup, 1, 1); + + destdesc.offset += dispatchBufferSize; + currentBatch++; + + // if we're about to end a batch, or we're done entirely, submit and flush + if(batchIndex == descriptorBatchSize - 1 || currentBatch == numSamples * numSlices) + { + ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); + + cmd = VK_NULL_HANDLE; + + // submit cmds and wait for idle so we can readback + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + } + } + } + + RDCASSERT(cmd == VK_NULL_HANDLE); + + ObjDisp(dev)->DestroyImageView(Unwrap(dev), srcView, NULL); +} + +void VulkanDebugManager::CopyDepthTex2DMSToBuffer(VkBuffer destBuffer, VkImage srcMS, + VkExtent3D extent, uint32_t baseSlice, + uint32_t numSlices, uint32_t baseSample, + uint32_t numSamples, VkFormat fmt) +{ + if(m_DepthMS2BufferPipe == VK_NULL_HANDLE) + return; + + VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; + uint32_t fmtIndex = 0; + switch(fmt) + { + case VK_FORMAT_D16_UNORM: fmtIndex = SHADER_D16_UNORM; break; + case VK_FORMAT_D16_UNORM_S8_UINT: + fmtIndex = SHADER_D16_UNORM_S8_UINT; + aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; + break; + case VK_FORMAT_X8_D24_UNORM_PACK32: fmtIndex = SHADER_X8_D24_UNORM_PACK32; break; + case VK_FORMAT_D24_UNORM_S8_UINT: + fmtIndex = SHADER_D24_UNORM_S8_UINT; + aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; + break; + case VK_FORMAT_D32_SFLOAT: fmtIndex = SHADER_D32_SFLOAT; break; + case VK_FORMAT_D32_SFLOAT_S8_UINT: + fmtIndex = SHADER_D32_SFLOAT_S8_UINT; + aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; + break; + default: RDCERR("Unexpected depth format: %d", fmt); return; + } + + VkDevice dev = m_Device; + + VkResult vkr = VK_SUCCESS; + + VkImageView srcDepthView = VK_NULL_HANDLE, srcStencilView = VK_NULL_HANDLE; + + VkImageViewCreateInfo viewInfo = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + NULL, + 0, + srcMS, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + fmt, + {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, + VK_COMPONENT_SWIZZLE_ZERO}, + { + VK_IMAGE_ASPECT_DEPTH_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS, + }, + }; + + vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &srcDepthView); + CheckVkResult(vkr); + NameUnwrappedVulkanObject(srcDepthView, "Depth MS -> Array srcDepthView"); + + if(aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) + { + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; + vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &srcStencilView); + CheckVkResult(vkr); + NameUnwrappedVulkanObject(srcStencilView, "Depth MS -> Array srcStencilView"); + } + + VkCommandBuffer cmd = VK_NULL_HANDLE; + VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; + + VkDescriptorImageInfo srcdesc[2]; + srcdesc[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + srcdesc[0].imageView = srcDepthView; + srcdesc[0].sampler = VK_NULL_HANDLE; // not used - we use texelFetch + srcdesc[1].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + srcdesc[1].imageView = srcStencilView; + srcdesc[1].sampler = VK_NULL_HANDLE; // not used - we use texelFetch + + if((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) == 0) + { + if(m_DummyStencilView != VK_NULL_HANDLE) + { + srcdesc[1].imageView = Unwrap(m_DummyStencilView); + } + else + { + // as a last fallback, hope that setting an incompatible view (float not int) will not break + // too badly. This only gets hit when the implementation has such poor format support that + // there are no uint formats that can be sampled as MSAA. + srcdesc[1].imageView = srcDepthView; + } + } + + const uint32_t dispatchBufferSize = GetByteSize(extent.width, extent.height, extent.depth, fmt, 0); + const uint32_t descriptorBatchSize = ARRAY_COUNT(m_BufferMSDescSet); + + VkDescriptorBufferInfo destdesc = {0}; + destdesc.buffer = destBuffer; + destdesc.offset = 0; + destdesc.range = dispatchBufferSize; + + uint32_t currentBatch = 0; + + for(uint32_t currentSlice = baseSlice; currentSlice < numSlices + baseSlice; currentSlice++) + { + for(uint32_t currentSample = baseSample; currentSample < numSamples + baseSample; currentSample++) + { + // if we don't have a current cmd buffer, start a new one + if(cmd == VK_NULL_HANDLE) + { + cmd = m_pDriver->GetNextCmd(); + + if(cmd == VK_NULL_HANDLE) + return; + + ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + + ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, + Unwrap(m_DepthMS2BufferPipe)); + } + const uint32_t batchIndex = currentBatch % descriptorBatchSize; + + VkWriteDescriptorSet writeSet[] = { + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_BufferMSDescSet[batchIndex]), 0, + 0, 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &srcdesc[0], NULL, NULL}, + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_BufferMSDescSet[batchIndex]), 1, + 0, 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &srcdesc[1], NULL, NULL}, + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_BufferMSDescSet[batchIndex]), 2, + 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, NULL, &destdesc, NULL}, + }; + + // for D16 textures, we need to multisample. + const uint32_t msDivider = fmt == VK_FORMAT_D16_UNORM ? 2 : 1; + const uint32_t workGroupDivider = MS_DISPATCH_LOCAL_SIZE * msDivider; + const uint32_t numWorkGroup = + AlignUp(extent.width * extent.height, workGroupDivider) / workGroupDivider; + const uint32_t maxInvoc = AlignUp(extent.width * extent.height, msDivider) / msDivider; + + Vec4u params[2] = { + {extent.width, currentSlice, currentSample, fmtIndex}, {maxInvoc, 0, 0, 0}, + }; + ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), ARRAY_COUNT(writeSet), writeSet, 0, NULL); + + ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, + Unwrap(m_BufferMSPipeLayout), 0, 1, + UnwrapPtr(m_BufferMSDescSet[batchIndex]), 0, NULL); + + ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_BufferMSPipeLayout), VK_SHADER_STAGE_ALL, + 0, sizeof(Vec4u) * 2, ¶ms); + + ObjDisp(cmd)->CmdDispatch(Unwrap(cmd), numWorkGroup, 1, 1); + + destdesc.offset += dispatchBufferSize; + currentBatch++; + + // if we're about to end a batch, or we're done entirely, submit and flush + if(batchIndex == descriptorBatchSize - 1 || currentBatch == numSamples * numSlices) + { + ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); + + cmd = VK_NULL_HANDLE; + + // submit cmds and wait for idle so we can readback + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + } + } + } + + RDCASSERT(cmd == VK_NULL_HANDLE); + + ObjDisp(dev)->DestroyImageView(Unwrap(dev), srcDepthView, NULL); + if(srcStencilView != VK_NULL_HANDLE) + ObjDisp(dev)->DestroyImageView(Unwrap(dev), srcStencilView, NULL); +} + +void VulkanDebugManager::CopyBufferToTex2DMS(VkImage destMS, VkBuffer srcBuffer, VkExtent3D extent, + uint32_t numSlices, uint32_t numSamples, VkFormat fmt) +{ + if(!m_pDriver->GetDeviceEnabledFeatures().shaderStorageImageMultisample || + !m_pDriver->GetDeviceEnabledFeatures().shaderStorageImageWriteWithoutFormat) + return; + + if(m_Buffer2MSPipe == VK_NULL_HANDLE) + return; + + if(IsDepthOrStencilFormat(fmt)) + { + CopyDepthBufferToTex2DMS(destMS, srcBuffer, extent, numSlices, numSamples, fmt); + return; + } + + VkDevice dev = m_Device; + + VkResult vkr = VK_SUCCESS; + + VkImageView destView; + + VkImageViewCreateInfo viewInfo = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + NULL, + 0, + destMS, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + VK_FORMAT_UNDEFINED, + {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY}, + { + VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS, + }, + }; + + uint32_t bs = GetByteSize(1, 1, 1, fmt, 0); + + if(bs == 1) + viewInfo.format = VK_FORMAT_R8_UINT; + else if(bs == 2) + viewInfo.format = VK_FORMAT_R16_UINT; + else if(bs == 4) + viewInfo.format = VK_FORMAT_R32_UINT; + else if(bs == 8) + viewInfo.format = VK_FORMAT_R32G32_UINT; + else if(bs == 16) + viewInfo.format = VK_FORMAT_R32G32B32A32_UINT; + + if(viewInfo.format == VK_FORMAT_UNDEFINED) + { + RDCERR("Can't copy Array to MS with format %s", ToStr(fmt).c_str()); + return; + } + + VkMarkerRegion region("CopyBufferToTex2DMS"); + + vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &destView); + CheckVkResult(vkr); + NameUnwrappedVulkanObject(destView, "Array -> MS destView"); + + VkCommandBuffer cmd = VK_NULL_HANDLE; + VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; + + const uint32_t dispatchBufferSize = GetByteSize(extent.width, extent.height, extent.depth, fmt, 0); + const uint32_t descriptorBatchSize = ARRAY_COUNT(m_BufferMSDescSet); + + VkDescriptorBufferInfo srcdesc = {0}; + srcdesc.buffer = srcBuffer; + srcdesc.offset = 0; + srcdesc.range = dispatchBufferSize; + + VkDescriptorImageInfo destdesc = {0}; + destdesc.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + destdesc.imageView = destView; + destdesc.sampler = VK_NULL_HANDLE; + + for(uint32_t currentSlice = 0; currentSlice < numSlices; currentSlice++) + { + for(uint32_t currentSample = 0; currentSample < numSamples; currentSample++) + { + // if we don't have a current cmd buffer, start a new one + if(cmd == VK_NULL_HANDLE) + { + cmd = m_pDriver->GetNextCmd(); + + if(cmd == VK_NULL_HANDLE) + return; + + ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + + ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, + Unwrap(m_Buffer2MSPipe)); + } + + const uint32_t batchIndex = (currentSlice * numSamples + currentSample) % descriptorBatchSize; + VkWriteDescriptorSet writeSet[] = { + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_BufferMSDescSet[batchIndex]), 2, + 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, NULL, &srcdesc, NULL}, + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_BufferMSDescSet[batchIndex]), 3, + 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &destdesc, NULL, NULL}, + }; + + // if the byte size is less than 4, we need to multisample. + const uint32_t msDivider = bs < 4 ? (4 / bs) : 1; + const uint32_t workGroupDivider = MS_DISPATCH_LOCAL_SIZE * msDivider; + const uint32_t numWorkGroup = + AlignUp(extent.width * extent.height, workGroupDivider) / workGroupDivider; + const uint32_t maxInvoc = AlignUp(extent.width * extent.height, msDivider) / msDivider; + + ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), ARRAY_COUNT(writeSet), writeSet, 0, NULL); + + ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, + Unwrap(m_BufferMSPipeLayout), 0, 1, + UnwrapPtr(m_BufferMSDescSet[batchIndex]), 0, NULL); + + Vec4u params[2] = { + {extent.width, currentSlice, currentSample, bs}, {maxInvoc, 0, 0, 0}, + }; + + ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_BufferMSPipeLayout), VK_SHADER_STAGE_ALL, + 0, sizeof(Vec4u) * 2, ¶ms); + + ObjDisp(cmd)->CmdDispatch(Unwrap(cmd), numWorkGroup, 1, 1); + + srcdesc.offset += dispatchBufferSize; + + // if we're about to end a batch, or we're done entirely, submit and flush + if(batchIndex == descriptorBatchSize - 1 || + (currentSlice == numSlices - 1 && currentSample == numSamples - 1)) + { + ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); + + cmd = VK_NULL_HANDLE; + + // submit cmds and wait for idle so we can readback + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + } + } + } + + RDCASSERT(cmd == VK_NULL_HANDLE); + + ObjDisp(dev)->DestroyImageView(Unwrap(dev), destView, NULL); +} + +void VulkanDebugManager::CopyDepthBufferToTex2DMS(VkImage destMS, VkBuffer srcBuffer, + VkExtent3D extent, uint32_t numSlices, + uint32_t numSamples, VkFormat fmt) +{ + VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; + + int pipeIndex = 0; + int formatIndex = 0; + switch(fmt) + { + case VK_FORMAT_D16_UNORM: + pipeIndex = 0; + formatIndex = SHADER_D16_UNORM; + break; + case VK_FORMAT_D16_UNORM_S8_UINT: + pipeIndex = 1; + aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; + formatIndex = SHADER_D16_UNORM_S8_UINT; + break; + case VK_FORMAT_X8_D24_UNORM_PACK32: + pipeIndex = 2; + formatIndex = SHADER_X8_D24_UNORM_PACK32; + break; + case VK_FORMAT_D24_UNORM_S8_UINT: + pipeIndex = 3; + aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; + formatIndex = SHADER_D24_UNORM_S8_UINT; + break; + case VK_FORMAT_D32_SFLOAT: + pipeIndex = 4; + formatIndex = SHADER_D32_SFLOAT; + break; + case VK_FORMAT_D32_SFLOAT_S8_UINT: + pipeIndex = 5; + aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; + formatIndex = SHADER_D32_SFLOAT_S8_UINT; + break; + default: RDCERR("Unexpected depth format: %d", fmt); return; + } + + // 0-based from 2x MSAA + uint32_t sampleIndex = SampleIndex((VkSampleCountFlagBits)numSamples) - 1; + + if(sampleIndex >= ARRAY_COUNT(m_DepthArray2MSPipe[0])) + { + RDCERR("Unsupported sample count %u", numSamples); + return; + } + + VkPipeline pipe = m_DepthArray2MSPipe[pipeIndex][sampleIndex]; + + if(pipe == VK_NULL_HANDLE) + return; + + VkMarkerRegion region("CopyDepthArrayToTex2DMS"); + + VkDevice dev = m_Device; + + VkResult vkr = VK_SUCCESS; + + VkImageView *destView = new VkImageView[numSlices]; + + VkDescriptorBufferInfo srcdesc = {0}; + srcdesc.buffer = srcBuffer; + srcdesc.offset = 0; + srcdesc.range = VK_WHOLE_SIZE; + + VkImageViewCreateInfo viewInfo = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + NULL, + 0, + destMS, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + fmt, + {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY}, + { + aspectFlags, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS, + }, + }; + + for(uint32_t i = 0; i < numSlices; i++) + { + viewInfo.subresourceRange.baseArrayLayer = i; + viewInfo.subresourceRange.layerCount = 1; + + vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &destView[i]); + CheckVkResult(vkr); + NameUnwrappedVulkanObject(destView[i], "Depth Array -> MS destView[i]"); + } + + VkWriteDescriptorSet writeSet[] = { + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_BufferMSDescSet[0]), 2, 0, 1, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, NULL, &srcdesc, NULL}, + }; + + ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), ARRAY_COUNT(writeSet), writeSet, 0, NULL); + + // create a bespoke framebuffer and renderpass for rendering + VkAttachmentDescription attDesc = {0, + fmt, + (VkSampleCountFlagBits)numSamples, + VK_ATTACHMENT_LOAD_OP_CLEAR, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_CLEAR, + VK_ATTACHMENT_STORE_OP_STORE, + VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_GENERAL}; + + VkAttachmentReference attRef = {0, VK_IMAGE_LAYOUT_GENERAL}; + + VkSubpassDescription sub = {}; + sub.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + sub.pDepthStencilAttachment = &attRef; + + VkRenderPassCreateInfo rpinfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + NULL, + 0, + 1, + &attDesc, + 1, + &sub, + 0, + NULL, // dependencies + }; + + VkRenderPass rp = VK_NULL_HANDLE; + + ObjDisp(dev)->CreateRenderPass(Unwrap(dev), &rpinfo, NULL, &rp); + + VkFramebufferCreateInfo fbinfo = { + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + NULL, + 0, + rp, + 1, + NULL, + extent.width, + extent.height, + 1, + }; + + VkFramebuffer *fb = new VkFramebuffer[numSlices]; + + for(uint32_t i = 0; i < numSlices; i++) + { + fbinfo.pAttachments = destView + i; + + vkr = ObjDisp(dev)->CreateFramebuffer(Unwrap(dev), &fbinfo, NULL, &fb[i]); + CheckVkResult(vkr); + } + + VkCommandBuffer cmd = m_pDriver->GetNextCmd(); + + if(cmd == VK_NULL_HANDLE) + return; + + VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, + + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; + + ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + + VkClearValue clearval = {}; + + VkRenderPassBeginInfo rpbegin = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, NULL, rp, VK_NULL_HANDLE, + {{0, 0}, {extent.width, extent.height}}, 1, &clearval, + }; + + uint32_t numStencil = 1; + + if(aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) + numStencil = 256; + + Vec4u params[2]; + params[0].x = numSamples; + params[0].y = formatIndex; + params[1].x = extent.width; + params[1].y = extent.height; + + ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(pipe)); + + for(uint32_t i = 0; i < numSlices; i++) + { + rpbegin.framebuffer = fb[i]; + + ObjDisp(cmd)->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); + + ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(m_BufferMSPipeLayout), 0, 1, + UnwrapPtr(m_BufferMSDescSet[0]), 0, NULL); + + VkViewport viewport = {0.0f, 0.0f, (float)extent.width, (float)extent.height, 0.0f, 1.0f}; + ObjDisp(cmd)->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); + + params[0].z = i; // currentSlice; + + for(uint32_t s = 0; s < numStencil; s++) + { + params[0].w = numStencil == 1 ? 1000 : s; // currentStencil; + + ObjDisp(cmd)->CmdSetStencilReference(Unwrap(cmd), VK_STENCIL_FACE_FRONT_AND_BACK, s); + ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_BufferMSPipeLayout), VK_SHADER_STAGE_ALL, + 0, sizeof(Vec4u) * ARRAY_COUNT(params), ¶ms); + ObjDisp(cmd)->CmdDraw(Unwrap(cmd), 4, 1, 0, 0); + } + + ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd)); + } + + ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); + + // submit cmds and wait for idle so we can readback + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + + for(uint32_t i = 0; i < numSlices; i++) + ObjDisp(dev)->DestroyFramebuffer(Unwrap(dev), fb[i], NULL); + ObjDisp(dev)->DestroyRenderPass(Unwrap(dev), rp, NULL); + + for(uint32_t i = 0; i < numSlices; i++) + ObjDisp(dev)->DestroyImageView(Unwrap(dev), destView[i], NULL); + + SAFE_DELETE_ARRAY(destView); + SAFE_DELETE_ARRAY(fb); +} diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 09e0bd3b7..fe8f9c4fc 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -3233,6 +3233,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, { bool wasms = false; bool resolve = params.resolve; + bool copyToBuffer = true; if(m_pDriver->m_CreationInfo.m_Image.find(tex) == m_pDriver->m_CreationInfo.m_Image.end()) { @@ -3305,6 +3306,10 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, VkResult vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); CheckVkResult(vkr); + uint32_t dataSize = 0; + VkBuffer readbackBuf = VK_NULL_HANDLE; + VkDeviceMemory readbackMem = VK_NULL_HANDLE; + if(imInfo.samples > 1) { // make image n-array instead of n-samples @@ -3709,46 +3714,36 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, } else if(wasms) { - // copy/expand multisampled live texture to array readback texture + dataSize = GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth, + imCreateInfo.format, s.mip); - // multiply array layers by sample count - uint32_t numSamples = (uint32_t)imInfo.samples; - imCreateInfo.mipLevels = 1; - imCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imCreateInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + // buffer size needs to be align to the int for shader writing + VkBufferCreateInfo bufInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, NULL, 0, + AlignUp(dataSize, 4U), VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT}; - if(IsDepthOrStencilFormat(imCreateInfo.format)) - imCreateInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - else - imCreateInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT; - - // create resolve texture - vt->CreateImage(Unwrap(dev), &imCreateInfo, NULL, &tmpImage); - wrappedTmpImage = tmpImage; - GetResourceManager()->WrapResource(Unwrap(dev), wrappedTmpImage); - tmpImageState = ImageState(wrappedTmpImage, ImageInfo(imCreateInfo), eFrameRef_None); - - NameVulkanObject(wrappedTmpImage, "GetTextureData tmpImage"); + vkr = vt->CreateBuffer(Unwrap(dev), &bufInfo, NULL, &readbackBuf); + CheckVkResult(vkr); VkMemoryRequirements mrq = {0}; - vt->GetImageMemoryRequirements(Unwrap(dev), tmpImage, &mrq); + + vt->GetBufferMemoryRequirements(Unwrap(dev), readbackBuf, &mrq); VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, mrq.size, - m_pDriver->GetGPULocalMemoryIndex(mrq.memoryTypeBits), + m_pDriver->GetReadbackMemoryIndex(mrq.memoryTypeBits), }; - - vkr = vt->AllocateMemory(Unwrap(dev), &allocInfo, NULL, &tmpMemory); + vkr = vt->AllocateMemory(Unwrap(dev), &allocInfo, NULL, &readbackMem); CheckVkResult(vkr); if(vkr != VK_SUCCESS) return; - vkr = vt->BindImageMemory(Unwrap(dev), tmpImage, tmpMemory, 0); + vkr = vt->BindBufferMemory(Unwrap(dev), readbackBuf, readbackMem, 0); CheckVkResult(vkr); - tmpImageState.InlineTransition(cmd, m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_GENERAL, 0, - VK_ACCESS_SHADER_WRITE_BIT, m_pDriver->GetImageTransitionInfo()); + // copy/expand multisampled live texture to readback buffer ImageBarrierSequence setupBarriers, cleanupBarriers; srcImageState->TempTransition(m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, @@ -3760,10 +3755,8 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, vkr = vt->EndCommandBuffer(Unwrap(cmd)); CheckVkResult(vkr); - // expand multisamples out to array - GetDebugManager()->CopyTex2DMSToArray(tmpImage, srcImage, imCreateInfo.extent, - imCreateInfo.arrayLayers / numSamples, numSamples, - imCreateInfo.format); + GetDebugManager()->CopyTex2DMSToBuffer(readbackBuf, srcImage, imCreateInfo.extent, s.slice, 1, + s.sample, 1, imCreateInfo.format); // fetch a new command buffer for copy & readback cmd = m_pDriver->GetNextCmd(); @@ -3774,10 +3767,6 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); CheckVkResult(vkr); - tmpImageState.InlineTransition(cmd, m_pDriver->m_QueueFamilyIdx, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_SHADER_WRITE_BIT, - VK_ACCESS_TRANSFER_READ_BIT, m_pDriver->GetImageTransitionInfo()); - m_pDriver->InlineCleanupImageBarriers(cmd, cleanupBarriers); if(!cleanupBarriers.empty()) @@ -3801,166 +3790,160 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, CheckVkResult(vkr); } - srcImage = tmpImage; - srcImageState = &tmpImageState; - s.slice = s.slice * numSamples + s.sample; - s.sample = 0; + // readback buffer has already been populated, no need to call CmdCopyImageToBuffer + copyToBuffer = false; } - ImageBarrierSequence cleanupBarriers; - + VkDeviceSize stencilOffset = 0; // if we have no tmpImage, we're copying directly from the real image - if(tmpImage == VK_NULL_HANDLE) + if(copyToBuffer) { - ImageBarrierSequence setupBarriers; - srcImageState->TempTransition(m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_ACCESS_TRANSFER_READ_BIT, setupBarriers, cleanupBarriers, - m_pDriver->GetImageTransitionInfo()); - m_pDriver->InlineSetupImageBarriers(cmd, setupBarriers); - m_pDriver->SubmitAndFlushImageStateBarriers(setupBarriers); - } - - VkImageAspectFlags copyAspects = VK_IMAGE_ASPECT_COLOR_BIT; - - if(isDepth) - copyAspects = VK_IMAGE_ASPECT_DEPTH_BIT; - else if(isStencil) - copyAspects = VK_IMAGE_ASPECT_STENCIL_BIT; - - VkBufferImageCopy copyregion[2] = { - { - 0, - 0, - 0, - {copyAspects, s.mip, s.slice, 1}, - { - 0, 0, 0, - }, - imCreateInfo.extent, - }, - // second region is only used for combined depth-stencil images - { - 0, - 0, - 0, - {VK_IMAGE_ASPECT_STENCIL_BIT, s.mip, s.slice, 1}, - { - 0, 0, 0, - }, - imCreateInfo.extent, - }, - }; - - for(int i = 0; i < 2; i++) - { - copyregion[i].imageExtent.width = RDCMAX(1U, copyregion[i].imageExtent.width >> s.mip); - copyregion[i].imageExtent.height = RDCMAX(1U, copyregion[i].imageExtent.height >> s.mip); - copyregion[i].imageExtent.depth = RDCMAX(1U, copyregion[i].imageExtent.depth >> s.mip); - } - - uint32_t dataSize = 0; - - // for most combined depth-stencil images this will be large enough for both to be copied - // separately, but for D24S8 we need to add extra space since they won't be copied packed - dataSize = GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth, - imCreateInfo.format, s.mip); - - if(imCreateInfo.format == VK_FORMAT_D24_UNORM_S8_UINT) - { - dataSize = AlignUp(dataSize, 4U); - dataSize += GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth, - VK_FORMAT_S8_UINT, s.mip); - } - - VkBufferCreateInfo bufInfo = { - VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - NULL, - 0, - dataSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - }; - - VkBuffer readbackBuf = VK_NULL_HANDLE; - vkr = vt->CreateBuffer(Unwrap(dev), &bufInfo, NULL, &readbackBuf); - CheckVkResult(vkr); - - VkMemoryRequirements mrq = {0}; - - vt->GetBufferMemoryRequirements(Unwrap(dev), readbackBuf, &mrq); - - VkMemoryAllocateInfo allocInfo = { - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, mrq.size, - m_pDriver->GetReadbackMemoryIndex(mrq.memoryTypeBits), - }; - - VkDeviceMemory readbackMem = VK_NULL_HANDLE; - vkr = vt->AllocateMemory(Unwrap(dev), &allocInfo, NULL, &readbackMem); - CheckVkResult(vkr); - - if(vkr != VK_SUCCESS) - return; - - vkr = vt->BindBufferMemory(Unwrap(dev), readbackBuf, readbackMem, 0); - CheckVkResult(vkr); - - if(isDepth && isStencil) - { - copyregion[1].bufferOffset = - GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth, - GetDepthOnlyFormat(imCreateInfo.format), s.mip); - - copyregion[1].bufferOffset = AlignUp(copyregion[1].bufferOffset, (VkDeviceSize)4); - - vt->CmdCopyImageToBuffer(Unwrap(cmd), srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - readbackBuf, 2, copyregion); - } - else if(imInfo.type == VK_IMAGE_TYPE_3D && params.remap != RemapTexture::NoRemap) - { - // copy in each slice from the 2D array we created to render out the 3D texture - for(uint32_t i = 0; i < imCreateInfo.arrayLayers; i++) + ImageBarrierSequence cleanupBarriers; + if(tmpImage == VK_NULL_HANDLE) { - copyregion[0].imageSubresource.baseArrayLayer = i; - copyregion[0].bufferOffset = - i * GetByteSize(imCreateInfo.extent.width, imCreateInfo.extent.height, 1, - imCreateInfo.format, s.mip); + ImageBarrierSequence setupBarriers; + srcImageState->TempTransition(m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_ACCESS_TRANSFER_READ_BIT, setupBarriers, cleanupBarriers, + m_pDriver->GetImageTransitionInfo()); + m_pDriver->InlineSetupImageBarriers(cmd, setupBarriers); + m_pDriver->SubmitAndFlushImageStateBarriers(setupBarriers); + } + + VkImageAspectFlags copyAspects = VK_IMAGE_ASPECT_COLOR_BIT; + + if(isDepth) + copyAspects = VK_IMAGE_ASPECT_DEPTH_BIT; + else if(isStencil) + copyAspects = VK_IMAGE_ASPECT_STENCIL_BIT; + + VkBufferImageCopy copyregion[2] = { + { + 0, + 0, + 0, + {copyAspects, s.mip, s.slice, 1}, + { + 0, 0, 0, + }, + imCreateInfo.extent, + }, + // second region is only used for combined depth-stencil images + { + 0, + 0, + 0, + {VK_IMAGE_ASPECT_STENCIL_BIT, s.mip, s.slice, 1}, + { + 0, 0, 0, + }, + imCreateInfo.extent, + }, + }; + + for(int i = 0; i < 2; i++) + { + copyregion[i].imageExtent.width = RDCMAX(1U, copyregion[i].imageExtent.width >> s.mip); + copyregion[i].imageExtent.height = RDCMAX(1U, copyregion[i].imageExtent.height >> s.mip); + copyregion[i].imageExtent.depth = RDCMAX(1U, copyregion[i].imageExtent.depth >> s.mip); + } + + dataSize = GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth, + imCreateInfo.format, s.mip); + + if(imCreateInfo.format == VK_FORMAT_D24_UNORM_S8_UINT) + { + // for most combined depth-stencil images this will be large enough for both to be copied + // separately, but for D24S8 we need to add extra space since they won't be copied packed + dataSize = AlignUp(dataSize, 4U); + dataSize += GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth, + VK_FORMAT_S8_UINT, s.mip); + } + + VkBufferCreateInfo bufInfo = { + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + NULL, + 0, + dataSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + }; + + vkr = vt->CreateBuffer(Unwrap(dev), &bufInfo, NULL, &readbackBuf); + CheckVkResult(vkr); + + VkMemoryRequirements mrq = {0}; + + vt->GetBufferMemoryRequirements(Unwrap(dev), readbackBuf, &mrq); + + VkMemoryAllocateInfo allocInfo = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, mrq.size, + m_pDriver->GetReadbackMemoryIndex(mrq.memoryTypeBits), + }; + vkr = vt->AllocateMemory(Unwrap(dev), &allocInfo, NULL, &readbackMem); + CheckVkResult(vkr); + + if(vkr != VK_SUCCESS) + return; + + vkr = vt->BindBufferMemory(Unwrap(dev), readbackBuf, readbackMem, 0); + CheckVkResult(vkr); + + if(isDepth && isStencil) + { + stencilOffset = GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth, + GetDepthOnlyFormat(imCreateInfo.format), s.mip); + stencilOffset = AlignUp(stencilOffset, (VkDeviceSize)4); + copyregion[1].bufferOffset = stencilOffset; + vt->CmdCopyImageToBuffer(Unwrap(cmd), srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + readbackBuf, 2, copyregion); + } + else if(imInfo.type == VK_IMAGE_TYPE_3D && params.remap != RemapTexture::NoRemap) + { + // copy in each slice from the 2D array we created to render out the 3D texture + for(uint32_t i = 0; i < imCreateInfo.arrayLayers; i++) + { + copyregion[0].imageSubresource.baseArrayLayer = i; + copyregion[0].bufferOffset = + i * GetByteSize(imCreateInfo.extent.width, imCreateInfo.extent.height, 1, + imCreateInfo.format, s.mip); + vt->CmdCopyImageToBuffer(Unwrap(cmd), srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + readbackBuf, 1, copyregion); + } + } + else + { + if(imInfo.type == VK_IMAGE_TYPE_3D) + copyregion[0].imageSubresource.baseArrayLayer = 0; + + // copy from desired subresource in srcImage to buffer vt->CmdCopyImageToBuffer(Unwrap(cmd), srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readbackBuf, 1, copyregion); } - } - else - { - if(imInfo.type == VK_IMAGE_TYPE_3D) - copyregion[0].imageSubresource.baseArrayLayer = 0; - // copy from desired subresource in srcImage to buffer - vt->CmdCopyImageToBuffer(Unwrap(cmd), srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - readbackBuf, 1, copyregion); - } - - // if we have no tmpImage, we're copying directly from the real image - if(tmpImage == VK_NULL_HANDLE) - { - m_pDriver->InlineCleanupImageBarriers(cmd, cleanupBarriers); - - if(!cleanupBarriers.empty()) + // if we have no tmpImage, we're copying directly from the real image + if(tmpImage == VK_NULL_HANDLE) { - // ensure this resolve happens before handing back the source image to the original queue - vkr = vt->EndCommandBuffer(Unwrap(cmd)); - CheckVkResult(vkr); + m_pDriver->InlineCleanupImageBarriers(cmd, cleanupBarriers); - m_pDriver->SubmitCmds(); - m_pDriver->FlushQ(); + if(!cleanupBarriers.empty()) + { + // ensure this resolve happens before handing back the source image to the original queue + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + CheckVkResult(vkr); - m_pDriver->SubmitAndFlushImageStateBarriers(cleanupBarriers); + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); - // fetch a new command buffer for remaining work - cmd = m_pDriver->GetNextCmd(); + m_pDriver->SubmitAndFlushImageStateBarriers(cleanupBarriers); - if(cmd == VK_NULL_HANDLE) - return; + // fetch a new command buffer for remaining work + cmd = m_pDriver->GetNextCmd(); - vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - CheckVkResult(vkr); + if(cmd == VK_NULL_HANDLE) + return; + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + CheckVkResult(vkr); + } } } @@ -4017,8 +4000,10 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, for(size_t i = 0; i < dataSize / sizeof(Vec4u); i++) output[i].y = float(input[i].y) / 255.0f; } - else if(isDepth && isStencil) + else if(isDepth && isStencil && copyToBuffer) { + // We only need to manually interleave if we use CmdCopyImageToBuffer. + // CopyDepthTex2DMS2Buffer will produce interleaved results. size_t pixelCount = std::max(1U, imCreateInfo.extent.width >> s.mip) * std::max(1U, imCreateInfo.extent.height >> s.mip) * std::max(1U, imCreateInfo.extent.depth >> s.mip); @@ -4026,13 +4011,13 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, // for some reason reading direct from mapped memory here is *super* slow on android (1.5s to // iterate over the image), so we memcpy to a temporary buffer. rdcarray tmp; - tmp.resize((size_t)copyregion[1].bufferOffset + pixelCount * sizeof(uint8_t)); + tmp.resize((size_t)stencilOffset + pixelCount * sizeof(uint8_t)); memcpy(tmp.data(), pData, tmp.size()); if(imCreateInfo.format == VK_FORMAT_D16_UNORM_S8_UINT) { uint16_t *dSrc = (uint16_t *)tmp.data(); - uint8_t *sSrc = (uint8_t *)(tmp.data() + copyregion[1].bufferOffset); + uint8_t *sSrc = (uint8_t *)(tmp.data() + stencilOffset); uint16_t *dDst = (uint16_t *)data.data(); uint16_t *sDst = dDst + 1; // interleaved, next pixel @@ -4056,7 +4041,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, // we can copy the depth from D24 as a 32-bit integer, since the remaining bits are garbage // and we overwrite them with stencil uint32_t *dSrc = (uint32_t *)tmp.data(); - uint8_t *sSrc = (uint8_t *)(tmp.data() + copyregion[1].bufferOffset); + uint8_t *sSrc = (uint8_t *)(tmp.data() + stencilOffset); uint32_t *dst = (uint32_t *)data.data(); @@ -4073,7 +4058,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, else { uint32_t *dSrc = (uint32_t *)tmp.data(); - uint8_t *sSrc = (uint8_t *)(tmp.data() + copyregion[1].bufferOffset); + uint8_t *sSrc = (uint8_t *)(tmp.data() + stencilOffset); uint32_t *dDst = (uint32_t *)data.data(); uint32_t *sDst = dDst + 1; // interleaved, next pixel diff --git a/renderdoc/driver/vulkan/vk_shader_cache.cpp b/renderdoc/driver/vulkan/vk_shader_cache.cpp index 3ed033c6b..dd5494da8 100644 --- a/renderdoc/driver/vulkan/vk_shader_cache.cpp +++ b/renderdoc/driver/vulkan/vk_shader_cache.cpp @@ -93,18 +93,6 @@ static const BuiltinShaderConfig builtinShaders[] = { rdcspv::ShaderStage::Geometry), BuiltinShaderConfig(BuiltinShader::TrisizeFS, EmbeddedResource(glsl_trisize_frag), rdcspv::ShaderStage::Fragment), - BuiltinShaderConfig(BuiltinShader::MS2ArrayCS, EmbeddedResource(glsl_ms2array_comp), - rdcspv::ShaderStage::Compute, - FeatureCheck::FormatlessWrite | FeatureCheck::NonMetalBackend), - BuiltinShaderConfig(BuiltinShader::Array2MSCS, EmbeddedResource(glsl_array2ms_comp), - rdcspv::ShaderStage::Compute, - FeatureCheck::ShaderMSAAStorage | FeatureCheck::FormatlessWrite | - FeatureCheck::NonMetalBackend), - BuiltinShaderConfig(BuiltinShader::DepthMS2ArrayFS, EmbeddedResource(glsl_depthms2arr_frag), - rdcspv::ShaderStage::Fragment, FeatureCheck::NonMetalBackend), - BuiltinShaderConfig(BuiltinShader::DepthArray2MSFS, EmbeddedResource(glsl_deptharr2ms_frag), - rdcspv::ShaderStage::Fragment, - FeatureCheck::SampleShading | FeatureCheck::NonMetalBackend), BuiltinShaderConfig(BuiltinShader::TexRemap, EmbeddedResource(glsl_texremap_frag), rdcspv::ShaderStage::Fragment, FeatureCheck::NoCheck, BuiltinShaderFlags::BaseTypeParameterised), @@ -132,6 +120,17 @@ static const BuiltinShaderConfig builtinShaders[] = { BuiltinShaderConfig(BuiltinShader::MinMaxResultCS, EmbeddedResource(glsl_minmaxresult_comp), rdcspv::ShaderStage::Compute, FeatureCheck::NoCheck, BuiltinShaderFlags::BaseTypeParameterised), + BuiltinShaderConfig(BuiltinShader::MS2BufferCS, EmbeddedResource(glsl_vk_ms2buffer_comp), + rdcspv::ShaderStage::Compute, FeatureCheck::NonMetalBackend), + BuiltinShaderConfig(BuiltinShader::DepthMS2BufferCS, EmbeddedResource(glsl_vk_depthms2buffer_comp), + rdcspv::ShaderStage::Compute, FeatureCheck::NonMetalBackend), + BuiltinShaderConfig(BuiltinShader::Buffer2MSCS, EmbeddedResource(glsl_vk_buffer2ms_comp), + rdcspv::ShaderStage::Compute, + FeatureCheck::ShaderMSAAStorage | FeatureCheck::FormatlessWrite | + FeatureCheck::NonMetalBackend), + BuiltinShaderConfig(BuiltinShader::DepthBuf2MSFS, EmbeddedResource(glsl_vk_depthbuf2ms_frag), + rdcspv::ShaderStage::Fragment, + FeatureCheck::SampleShading | FeatureCheck::NonMetalBackend), }; RDCCOMPILE_ASSERT(ARRAY_COUNT(builtinShaders) == arraydim(), @@ -243,10 +242,8 @@ VulkanShaderCache::VulkanShaderCache(WrappedVulkan *driver) rdcspv::CompilationSettings compileSettings; compileSettings.lang = rdcspv::InputLanguage::VulkanGLSL; - m_MS2ArraySupported = - PassesChecks(builtinShaders[(size_t)BuiltinShader::MS2ArrayCS], driverVersion, availFeatures); - m_Array2MSSupported = - PassesChecks(builtinShaders[(size_t)BuiltinShader::Array2MSCS], driverVersion, availFeatures); + m_Buffer2MSSupported = + PassesChecks(builtinShaders[(size_t)BuiltinShader::Buffer2MSCS], driverVersion, availFeatures); for(auto i : indices()) { diff --git a/renderdoc/driver/vulkan/vk_shader_cache.h b/renderdoc/driver/vulkan/vk_shader_cache.h index 81343bd7f..186881b8a 100644 --- a/renderdoc/driver/vulkan/vk_shader_cache.h +++ b/renderdoc/driver/vulkan/vk_shader_cache.h @@ -47,10 +47,6 @@ enum class BuiltinShader QuadWriteFS, TrisizeGS, TrisizeFS, - MS2ArrayCS, - Array2MSCS, - DepthMS2ArrayFS, - DepthArray2MSFS, TexRemap, PixelHistoryMSCopyCS, PixelHistoryMSCopyDepthCS, @@ -60,6 +56,10 @@ enum class BuiltinShader HistogramCS, MinMaxTileCS, MinMaxResultCS, + MS2BufferCS, + DepthMS2BufferCS, + Buffer2MSCS, + DepthBuf2MSFS, Count, }; @@ -112,8 +112,7 @@ public: void MakeGraphicsPipelineInfo(VkGraphicsPipelineCreateInfo &pipeCreateInfo, ResourceId pipeline); void MakeComputePipelineInfo(VkComputePipelineCreateInfo &pipeCreateInfo, ResourceId pipeline); - bool IsMS2ArraySupported() { return m_MS2ArraySupported; } - bool IsArray2MSSupported() { return m_Array2MSSupported; } + bool IsBuffer2MSSupported() { return m_Buffer2MSSupported; } void SetCaching(bool enabled) { m_CacheShaders = enabled; } private: static const uint32_t m_ShaderCacheMagic = 0xf00d00d5; @@ -128,7 +127,7 @@ private: bytebuf m_PipeCacheBlob; VkPipelineCache m_PipelineCache = VK_NULL_HANDLE; - bool m_MS2ArraySupported = false, m_Array2MSSupported = false; + bool m_Buffer2MSSupported = false; bool m_ShaderCacheDirty = false, m_CacheShaders = false; std::map m_ShaderCache; diff --git a/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp index 5c26e46fb..1278f16cb 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp @@ -422,7 +422,7 @@ void WrappedVulkan::vkGetDeviceImageMemoryRequirements(VkDevice device, { if(!IsDepthOrStencilFormat(info->format)) { - if(GetDebugManager() && GetShaderCache()->IsArray2MSSupported()) + if(GetDebugManager() && GetShaderCache()->IsBuffer2MSSupported()) info->usage |= VK_IMAGE_USAGE_STORAGE_BIT; } else diff --git a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp index 0fe13864a..df68b5030 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp @@ -697,7 +697,7 @@ void WrappedVulkan::PatchAttachment(VkFramebufferAttachmentImageInfo *att, VkFor if(!IsDepthOrStencilFormat(imgFormat)) { - if(GetDebugManager() && GetShaderCache()->IsArray2MSSupported()) + if(GetDebugManager() && GetShaderCache()->IsBuffer2MSSupported()) att->usage |= VK_IMAGE_USAGE_STORAGE_BIT; } else diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index 1f32aa933..163713d99 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -1989,7 +1989,7 @@ bool WrappedVulkan::Serialise_vkCreateImage(SerialiserType &ser, VkDevice device // of capability or because we disabled it as a workaround then we don't need this // capability (and it might be the bug we're trying to work around by disabling the // pipeline) - if(GetShaderCache()->IsArray2MSSupported()) + if(GetShaderCache()->IsBuffer2MSSupported()) CreateInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT; } else @@ -2197,7 +2197,7 @@ VkResult WrappedVulkan::vkCreateImage(VkDevice device, const VkImageCreateInfo * { // need to check the debug manager here since we might be creating this internal image from // its constructor - if(GetDebugManager() && GetShaderCache()->IsArray2MSSupported()) + if(GetDebugManager() && GetShaderCache()->IsBuffer2MSSupported()) createInfo_adjusted.usage |= VK_IMAGE_USAGE_STORAGE_BIT; } else @@ -2522,7 +2522,7 @@ void WrappedVulkan::PatchImageViewUsage(VkImageViewUsageCreateInfo *usage, VkFor if(!IsDepthOrStencilFormat(imgFormat)) { - if(GetDebugManager() && GetShaderCache()->IsArray2MSSupported()) + if(GetDebugManager() && GetShaderCache()->IsBuffer2MSSupported()) usage->usage |= VK_IMAGE_USAGE_STORAGE_BIT; } else