diff --git a/renderdoc/driver/vulkan/vk_postvs.cpp b/renderdoc/driver/vulkan/vk_postvs.cpp index 16ef8f7c1..c6ede3b72 100644 --- a/renderdoc/driver/vulkan/vk_postvs.cpp +++ b/renderdoc/driver/vulkan/vk_postvs.cpp @@ -589,10 +589,13 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, io.variable = patchData.inputs[i].ID; - rdcspv::Scalar scalarType = rdcspv::scalar(refl.inputSignature[i].varType); + VarType vType = refl.inputSignature[i].varType; - // doubles are loaded as uvec4 and then packed in pairs, so we need to declare vec4ID as uvec4 - if(refl.inputSignature[i].varType == VarType::Double) + rdcspv::Scalar scalarType = rdcspv::scalar(vType); + + // 64-bit values are loaded as uvec4 and then packed in pairs, so we need to declare vec4ID as + // uvec4 + if(vType == VarType::Double || vType == VarType::ULong || vType == VarType::SLong) { io.fetchVec4Type = io.vec4Type = editor.DeclareType(rdcspv::Vector(rdcspv::scalar(), 4)); @@ -602,7 +605,7 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, io.vec4Type = editor.DeclareType(rdcspv::Vector(scalarType, 4)); // if the underlying scalar is actually - switch(refl.inputSignature[i].varType) + switch(vType) { case VarType::Half: io.fetchVec4Type = editor.DeclareType(rdcspv::Vector(rdcspv::scalar(), 4)); @@ -1100,6 +1103,8 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, for(size_t i = 0; i < refl.inputSignature.size(); i++) { + VarType vType = refl.inputSignature[i].varType; + ShaderBuiltin builtin = refl.inputSignature[i].systemValue; if(builtin != ShaderBuiltin::Undefined) { @@ -1159,7 +1164,7 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, if(valueID) { - if(VarTypeCompType(refl.inputSignature[i].varType) == compType) + if(VarTypeCompType(vType) == compType) { ops.add(rdcspv::OpStore(ins[i].variable, valueID)); } @@ -1218,9 +1223,9 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, } } - if(refl.inputSignature[i].varType == VarType::Double) + if(vType == VarType::Double || vType == VarType::ULong || vType == VarType::SLong) { - // since doubles are packed into two uints, we need to multiply the index by two + // since 64-bit vlaues are packed into two uints, we need to multiply the index by two idx = ops.add(rdcspv::OpIMul(u32Type, editor.MakeId(), idx, editor.AddConstantImmediate(2))); } @@ -1255,9 +1260,9 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, // size (typically ushort or half) then convert here if(ins[i].fetchVec4Type != ins[i].vec4Type) { - if(VarTypeCompType(refl.inputSignature[i].varType) == CompType::Float) + if(VarTypeCompType(vType) == CompType::Float) result = ops.add(rdcspv::OpFConvert(ins[i].vec4Type, editor.MakeId(), result)); - else if(VarTypeCompType(refl.inputSignature[i].varType) == CompType::UInt) + else if(VarTypeCompType(vType) == CompType::UInt) result = ops.add(rdcspv::OpUConvert(ins[i].vec4Type, editor.MakeId(), result)); else result = ops.add(rdcspv::OpSConvert(ins[i].vec4Type, editor.MakeId(), result)); @@ -1265,9 +1270,9 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, uint32_t comp = Bits::CountTrailingZeroes(uint32_t(refl.inputSignature[i].regChannelMask)); - if(refl.inputSignature[i].varType == VarType::Double) + if(vType == VarType::Double || vType == VarType::ULong || vType == VarType::SLong) { - // since doubles are packed into two uints, we now need to fetch more data and do + // since 64-bit values are packed into two uints, we now need to fetch more data and do // packing. We can fetch the data unconditionally since it's harmless to read out of the // bounds of the buffer @@ -1304,10 +1309,21 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, editor.SetName(packed, StringFormat::Fmt("packed_%c", swizzle[c])); - // double comp = PackDouble2x32(packed); - comps[c] = ops.add(rdcspv::OpGLSL450(editor.DeclareType(rdcspv::scalar()), - editor.MakeId(), glsl450, - rdcspv::GLSLstd450::PackDouble2x32, {packed})); + if(vType == VarType::Double) + { + // double comp = PackDouble2x32(packed); + comps[c] = ops.add(rdcspv::OpGLSL450(editor.DeclareType(rdcspv::scalar()), + editor.MakeId(), glsl450, + rdcspv::GLSLstd450::PackDouble2x32, {packed})); + } + else + { + rdcspv::Scalar s = (vType == VarType::ULong) ? rdcspv::scalar() + : rdcspv::scalar(); + + // [u]int64 comp = Bitcast(packed); + comps[c] = ops.add(rdcspv::OpBitcast(editor.DeclareType(s), editor.MakeId(), packed)); + } } // if there's only one component it's ready, otherwise construct a vector @@ -2133,7 +2149,7 @@ void VulkanReplay::FetchVSOut(uint32_t eventId, VulkanRenderState &state) VkFormat origFormat = attrDesc.format; VkFormat expandedFormat = VK_FORMAT_R32G32B32A32_SFLOAT; - if(IsDoubleFormat(origFormat)) + if(Is64BitFormat(origFormat)) expandedFormat = VK_FORMAT_R32G32B32A32_UINT; else if(IsUIntFormat(origFormat)) expandedFormat = VK_FORMAT_R32G32B32A32_UINT; @@ -2143,8 +2159,8 @@ void VulkanReplay::FetchVSOut(uint32_t eventId, VulkanRenderState &state) uint32_t origElemSize = GetByteSize(1, 1, 1, origFormat, 0); uint32_t elemSize = GetByteSize(1, 1, 1, expandedFormat, 0); - // doubles are packed as uvec2 - if(IsDoubleFormat(origFormat)) + // 64-bit values are packed as uvec2 + if(Is64BitFormat(origFormat)) elemSize *= 2; // used for interpreting the original data, if we're upcasting @@ -2253,14 +2269,14 @@ void VulkanReplay::FetchVSOut(uint32_t eventId, VulkanRenderState &state) uint32_t zero = 0; // upcasting path - if(IsDoubleFormat(origFormat)) + if(Is64BitFormat(origFormat)) { while(src < origVBEnd && dst < dstEnd) { - // the double is already in "packed uvec2" order, with least significant 32-bits - // first, so we can copy directly - memcpy(dst, src, sizeof(double) * fmt.compCount); - dst += sizeof(double) * fmt.compCount; + // the 64-bit value (especially for doubles) is already in "packed uvec2" order, + // with least significant 32-bits first, so we can copy directly + memcpy(dst, src, sizeof(uint64_t) * fmt.compCount); + dst += sizeof(uint64_t) * fmt.compCount; // fill up to *8* zeros not 4, since we're filling two for every component for(uint8_t c = fmt.compCount * 2; c < 8; c++) diff --git a/renderdoc/driver/vulkan/vk_resources.cpp b/renderdoc/driver/vulkan/vk_resources.cpp index 6c26d36b0..51cec9dce 100644 --- a/renderdoc/driver/vulkan/vk_resources.cpp +++ b/renderdoc/driver/vulkan/vk_resources.cpp @@ -344,7 +344,7 @@ bool IsSRGBFormat(VkFormat f) return false; } -bool IsDoubleFormat(VkFormat f) +bool Is64BitFormat(VkFormat f) { switch(f) { diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index 21e0d335e..aa1b93afd 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -2378,7 +2378,7 @@ bool IsStencilFormat(VkFormat f); bool IsStencilOnlyFormat(VkFormat f); bool IsSRGBFormat(VkFormat f); bool IsUIntFormat(VkFormat f); -bool IsDoubleFormat(VkFormat f); +bool Is64BitFormat(VkFormat f); bool IsSIntFormat(VkFormat f); bool IsYUVFormat(VkFormat f); VkImageAspectFlags FormatImageAspects(VkFormat f); diff --git a/util/test/demos/vk/vk_vertex_attr_zoo.cpp b/util/test/demos/vk/vk_vertex_attr_zoo.cpp index 2bb87f132..b10c5da22 100644 --- a/util/test/demos/vk/vk_vertex_attr_zoo.cpp +++ b/util/test/demos/vk/vk_vertex_attr_zoo.cpp @@ -35,11 +35,13 @@ RD_TEST(VK_Vertex_Attr_Zoo, VulkanGraphicsTest) { int16_t i16[4]; uint16_t u16[4]; - double df[2]; + double df[3]; float arr0[2]; float arr1[2]; float mat0[2]; float mat1[2]; + uint64_t lf[3]; + int64_t slf[3]; }; std::string vertex = R"EOSHADER( @@ -50,10 +52,14 @@ layout(location = 3) in uvec2 InUInt; layout(location = 3, component = 2) in uint InUInt1; layout(location = 3, component = 3) in uint InUInt2; #if DOUBLES -layout(location = 4) in dvec2 InDouble; +layout(location = 4) in dvec3 InDouble; +#endif +layout(location = 6) in vec2 InArray[2]; +layout(location = 8) in mat2x2 InMatrix; +#if LONGS +layout(location = 10) in u64vec3 InULong; +layout(location = 12) in i64vec3 InSLong; #endif -layout(location = 5) in vec2 InArray[2]; -layout(location = 7) in mat2x2 InMatrix; layout(location = 0) out vec4 OutSNorm; layout(location = 1) out vec4 OutUNorm; @@ -62,10 +68,14 @@ layout(location = 3) flat out uvec2 OutUInt; layout(location = 3, component = 2) flat out uint OutUInt1; layout(location = 3, component = 3) flat out uint OutUInt2; #if DOUBLES -layout(location = 4) out dvec2 OutDouble; +layout(location = 4) out dvec3 OutDouble; +#endif +layout(location = 6) out vec2 OutArray[2]; +layout(location = 8) out mat2x2 OutMatrix; +#if LONGS +layout(location = 10) out u64vec3 OutULong; +layout(location = 12) out i64vec3 OutSLong; #endif -layout(location = 5) out vec2 OutArray[2]; -layout(location = 7) out mat2x2 OutMatrix; void main() { @@ -85,6 +95,10 @@ void main() OutUNorm = InUNorm; OutArray = InArray; OutMatrix = InMatrix; +#if LONGS + OutULong = InULong; + OutSLong = InSLong; +#endif } )EOSHADER"; @@ -97,10 +111,14 @@ layout(location = 3) flat in uvec2 InUInt; layout(location = 3, component = 2) flat in uint InUInt1; layout(location = 3, component = 3) flat in uint InUInt2; #if DOUBLES -layout(location = 4) flat in dvec2 InDouble; +layout(location = 4) flat in dvec3 InDouble; +#endif +layout(location = 6) in vec2 InArray[2]; +layout(location = 8) in mat2x2 InMatrix; +#if LONGS +layout(location = 10) flat in u64vec3 InULong; +layout(location = 12) flat in i64vec3 InSLong; #endif -layout(location = 5) in vec2 InArray[2]; -layout(location = 7) in mat2x2 InMatrix; layout(location = 0, index = 0) out vec4 Color; @@ -131,6 +149,13 @@ void main() if(clamp(InDouble, -10.0, 10.0) != InDouble) Color = vec4(0.5f, 0, 0, 1); #endif + +#if LONGS + if(InULong.x < 10000000000UL || InULong.y < 10000000000UL || InULong.z < 10000000000UL) + Color = vec4(0.6f, 0, 0, 1); + if(InSLong.x > -10000000000UL || InSLong.y > -10000000000UL || InSLong.z > -10000000000UL) + Color = vec4(0.7f, 0, 0, 1); +#endif } )EOSHADER"; @@ -146,10 +171,14 @@ layout(location = 3) flat in uvec2 InUInt[3]; layout(location = 3, component = 2) flat in uint InUInt1[3]; layout(location = 3, component = 3) flat in uint InUInt2[3]; #if DOUBLES -layout(location = 4) in dvec2 InDouble[3]; +layout(location = 4) in dvec3 InDouble[3]; +#endif +layout(location = 6) in vec2 InArray[3][2]; +layout(location = 8) in mat2x2 InMatrix[3]; +#if LONGS +layout(location = 10) in u64vec3 InULong[3]; +layout(location = 12) in i64vec3 InSLong[3]; #endif -layout(location = 5) in vec2 InArray[3][2]; -layout(location = 7) in mat2x2 InMatrix[3]; layout(location = 0) out vec4 OutSNorm; layout(location = 1) out vec4 OutUNorm; @@ -158,10 +187,14 @@ layout(location = 3) flat out uvec2 OutUInt; layout(location = 3, component = 2) flat out uint OutUInt1; layout(location = 3, component = 3) flat out uint OutUInt2; #if DOUBLES -layout(location = 4) out dvec2 OutDouble; +layout(location = 4) out dvec3 OutDouble; +#endif +layout(location = 6) out vec2 OutArray[2]; +layout(location = 8) out mat2x2 OutMatrix; +#if LONGS +layout(location = 10) out u64vec3 OutULong; +layout(location = 12) out i64vec3 OutSLong; #endif -layout(location = 5) out vec2 OutArray[2]; -layout(location = 7) out mat2x2 OutMatrix; void main() { @@ -180,6 +213,10 @@ void main() OutUNorm = InUNorm[i]; OutArray = InArray[i]; OutMatrix = InMatrix[i]; +#if LONGS + OutULong = InULong[i]; + OutSLong = InSLong[i]; +#endif EmitVertex(); } @@ -297,6 +334,8 @@ void main() // radv doesn't support doubles :( optFeatures.shaderFloat64 = VK_TRUE; + optFeatures.shaderInt64 = VK_TRUE; + VulkanGraphicsTest::Prepare(argc, argv); if(!Avail.empty()) @@ -322,10 +361,20 @@ void main() return 3; VkFormatProperties props = {}; - vkGetPhysicalDeviceFormatProperties(phys, VK_FORMAT_R64G64_SFLOAT, &props); + vkGetPhysicalDeviceFormatProperties(phys, VK_FORMAT_R64G64B64_SFLOAT, &props); const bool doubles = (props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) != 0; + props = {}; + vkGetPhysicalDeviceFormatProperties(phys, VK_FORMAT_R64G64B64_SINT, &props); + const bool slongs = (props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) != 0; + + props = {}; + vkGetPhysicalDeviceFormatProperties(phys, VK_FORMAT_R64G64B64_UINT, &props); + const bool ulongs = (props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) != 0; + + const bool longs = slongs && ulongs; + VkPipelineLayout layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo()); vkh::GraphicsPipelineCreateInfo pipeCreateInfo; @@ -340,18 +389,32 @@ void main() vkh::vertexAttrFormatted(1, 0, vertin, u16, VK_FORMAT_R16G16B16A16_UNORM), vkh::vertexAttrFormatted(2, 0, vertin, u16, VK_FORMAT_R16G16B16A16_USCALED), vkh::vertexAttrFormatted(3, 0, vertin, u16, VK_FORMAT_R16G16B16A16_UINT), - vkh::vertexAttrFormatted(5, 0, vertin, arr0, VK_FORMAT_R32G32_SFLOAT), - vkh::vertexAttrFormatted(6, 0, vertin, arr1, VK_FORMAT_R32G32_SFLOAT), - vkh::vertexAttrFormatted(7, 0, vertin, mat0, VK_FORMAT_R32G32_SFLOAT), - vkh::vertexAttrFormatted(8, 0, vertin, mat1, VK_FORMAT_R32G32_SFLOAT), + vkh::vertexAttrFormatted(6, 0, vertin, arr0, VK_FORMAT_R32G32_SFLOAT), + vkh::vertexAttrFormatted(7, 0, vertin, arr1, VK_FORMAT_R32G32_SFLOAT), + vkh::vertexAttrFormatted(8, 0, vertin, mat0, VK_FORMAT_R32G32_SFLOAT), + vkh::vertexAttrFormatted(9, 0, vertin, mat1, VK_FORMAT_R32G32_SFLOAT), }; std::string common = "#version 450 core\n\n"; + if(longs) + { + pipeCreateInfo.vertexInputState.vertexAttributeDescriptions.push_back( + vkh::vertexAttrFormatted(10, 0, vertin, lf, VK_FORMAT_R64G64B64_UINT)); + pipeCreateInfo.vertexInputState.vertexAttributeDescriptions.push_back( + vkh::vertexAttrFormatted(12, 0, vertin, slf, VK_FORMAT_R64G64B64_SINT)); + + common += "#extension GL_ARB_gpu_shader_int64 : require\n\n#define LONGS 1\n\n"; + } + else + { + common += "#define LONGS 0\n\n"; + } + if(doubles) { pipeCreateInfo.vertexInputState.vertexAttributeDescriptions.push_back( - vkh::vertexAttrFormatted(4, 0, vertin, df, VK_FORMAT_R64G64_SFLOAT)); + vkh::vertexAttrFormatted(4, 0, vertin, df, VK_FORMAT_R64G64B64_SFLOAT)); common += "#define DOUBLES 1\n\n"; } @@ -381,29 +444,35 @@ void main() { {32767, -32768, 32767, -32767}, {12345, 6789, 1234, 567}, - {9.8765432109, -5.6789012345}, + {9.8765432109, -5.6789012345, 1.2345}, {1.0f, 2.0f}, {3.0f, 4.0f}, {7.0f, 8.0f}, {9.0f, 10.0f}, + {10000012345, 10000006789, 10000001234}, + {-10000012345, -10000006789, -10000001234}, }, { {32766, -32766, 16000, -16000}, {56, 7890, 123, 4567}, - {-7.89012345678, 6.54321098765}, + {-7.89012345678, 6.54321098765, 1.2345}, {11.0f, 12.0f}, {13.0f, 14.0f}, {17.0f, 18.0f}, {19.0f, 20.0f}, + {10000000056, 10000007890, 10000000123}, + {-10000000056, -10000007890, -10000000123}, }, { {5, -5, 0, 0}, {8765, 43210, 987, 65432}, - {0.1234567890123, 4.5678901234}, + {0.1234567890123, 4.5678901234, 1.2345}, {21.0f, 22.0f}, {23.0f, 24.0f}, {27.0f, 28.0f}, {29.0f, 30.0f}, + {10000008765, 10000043210, 10000000987}, + {-10000008765, -10000043210, -10000000987}, }, }; @@ -430,6 +499,9 @@ void main() if(doubles) setMarker(cmd, "DoublesEnabled"); + if(longs) + setMarker(cmd, "LongsEnabled"); + vkCmdBeginRenderPass( cmd, vkh::RenderPassBeginInfo(mainWindow->rp, mainWindow->GetFB(), mainWindow->scissor), VK_SUBPASS_CONTENTS_INLINE); diff --git a/util/test/rdtest/analyse.py b/util/test/rdtest/analyse.py index b513efcef..229870bf0 100644 --- a/util/test/rdtest/analyse.py +++ b/util/test/rdtest/analyse.py @@ -163,7 +163,7 @@ def get_postvs_attrs(controller: rd.ReplayController, mesh: rd.MeshFormat, data_ # Construct a resource format for this element attr.mesh.format = rd.ResourceFormat() - attr.mesh.format.compByteWidth = 8 if sig.varType == rd.VarType.Double else 4 + attr.mesh.format.compByteWidth = rd.VarTypeByteSize(sig.varType) attr.mesh.format.compCount = sig.compCount attr.mesh.format.compType = rd.VarTypeCompType(sig.varType) attr.mesh.format.type = rd.ResourceFormatType.Regular diff --git a/util/test/tests/Vulkan/VK_Vertex_Attr_Zoo.py b/util/test/tests/Vulkan/VK_Vertex_Attr_Zoo.py index b28fc77e3..3a3c27efb 100644 --- a/util/test/tests/Vulkan/VK_Vertex_Attr_Zoo.py +++ b/util/test/tests/Vulkan/VK_Vertex_Attr_Zoo.py @@ -21,11 +21,13 @@ class VK_Vertex_Attr_Zoo(rdtest.TestCase): 'UInt': [12345, 6789], 'UInt1': [1234], 'UInt2': [567], - 'Double': [9.8765432109, -5.6789012345], + 'Double': [9.8765432109, -5.6789012345, 1.2345], 'Array[0]': [1.0, 2.0], 'Array[1]': [3.0, 4.0], 'Matrix:col0': [7.0, 8.0], 'Matrix:col1': [9.0, 10.0], + 'ULong': [10000012345, 10000006789, 10000001234], + 'SLong': [-10000012345, -10000006789, -10000001234], }, 1: { 'SNorm': [32766.0/32767.0, -32766.0/32767.0, 16000.0/32767.0, -16000.0/32767.0], @@ -34,11 +36,13 @@ class VK_Vertex_Attr_Zoo(rdtest.TestCase): 'UInt': [56, 7890], 'UInt1': [123], 'UInt2': [4567], - 'Double': [-7.89012345678, 6.54321098765], + 'Double': [-7.89012345678, 6.54321098765, 1.2345], 'Array[0]': [11.0, 12.0], 'Array[1]': [13.0, 14.0], 'Matrix:col0': [17.0, 18.0], 'Matrix:col1': [19.0, 20.0], + 'ULong': [10000000056, 10000007890, 10000000123], + 'SLong': [-10000000056, -10000007890, -10000000123], }, 2: { 'SNorm': [5.0/32767.0, -5.0/32767.0, 0.0, 0.0], @@ -47,15 +51,18 @@ class VK_Vertex_Attr_Zoo(rdtest.TestCase): 'UInt': [8765, 43210], 'UInt1': [987], 'UInt2': [65432], - 'Double': [0.1234567890123, 4.5678901234], + 'Double': [0.1234567890123, 4.5678901234, 1.2345], 'Array[0]': [21.0, 22.0], 'Array[1]': [23.0, 24.0], 'Matrix:col0': [27.0, 28.0], 'Matrix:col1': [29.0, 30.0], + 'ULong': [10000008765, 10000043210, 10000000987], + 'SLong': [-10000008765, -10000043210, -10000000987], }, } doubles = self.find_action('DoublesEnabled') is not None + longs = self.find_action('LongsEnabled') is not None # Copy the ref values and prepend 'In' in_ref = {} @@ -66,6 +73,8 @@ class VK_Vertex_Attr_Zoo(rdtest.TestCase): continue if not doubles and 'Double' in key: continue + if not longs and 'Long' in key: + continue in_ref[idx]['In' + key] = ref[idx][key] in_ref[idx]['InUInt2'] = ref[idx]['UInt'] + ref[idx]['UInt1'] + ref[idx]['UInt2'] @@ -77,6 +86,8 @@ class VK_Vertex_Attr_Zoo(rdtest.TestCase): for key in ref[idx]: if not doubles and 'Double' in key: continue + if not longs and 'Long' in key: + continue out_ref[idx]['Out' + key] = ref[idx][key] vsout_ref = copy.deepcopy(out_ref)