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