diff --git a/renderdoc/driver/shaders/spirv/spirv_processor.h b/renderdoc/driver/shaders/spirv/spirv_processor.h index 76e4cc369..779098ff0 100644 --- a/renderdoc/driver/shaders/spirv/spirv_processor.h +++ b/renderdoc/driver/shaders/spirv/spirv_processor.h @@ -27,6 +27,7 @@ #include #include #include +#include "3rdparty/half/half.hpp" #include "api/replay/rdcarray.h" #include "api/replay/rdcpair.h" #include "api/replay/rdcstr.h" @@ -118,6 +119,7 @@ SCALAR_TYPE(int32_t, Op::TypeInt, 32, true); SCALAR_TYPE(int64_t, Op::TypeInt, 64, true); SCALAR_TYPE(float, Op::TypeFloat, 32, false); SCALAR_TYPE(double, Op::TypeFloat, 64, false); +SCALAR_TYPE(half_float::half, Op::TypeFloat, 16, false); struct Vector { diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index fa51db821..3b3eb3e2b 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -541,8 +541,6 @@ private: // allocation objects with size by incrementally allocating larger blocks. VkDeviceSize m_MemoryBlockSize[arraydim()] = {}; - MemoryAllocation AllocateMemoryForResource(VkImage im, MemoryScope scope, MemoryType type); - MemoryAllocation AllocateMemoryForResource(VkBuffer buf, MemoryScope scope, MemoryType type); void FreeAllMemory(MemoryScope scope); void FreeMemoryAllocation(MemoryAllocation alloc); @@ -1052,6 +1050,9 @@ public: uint32_t GetUploadMemoryIndex(uint32_t resourceCompatibleBitmask); uint32_t GetGPULocalMemoryIndex(uint32_t resourceCompatibleBitmask); + MemoryAllocation AllocateMemoryForResource(VkImage im, MemoryScope scope, MemoryType type); + MemoryAllocation AllocateMemoryForResource(VkBuffer buf, MemoryScope scope, MemoryType type); + void ChooseMemoryIndices(); EventFlags GetEventFlags(uint32_t eid) { return m_EventFlags[eid]; } diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 1efe99388..90a83850c 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -3931,9 +3931,12 @@ void ShaderDebugData::Init(WrappedVulkan *driver, VkDescriptorPool descriptorPoo {7, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, NULL}, // ShaderDebugBind::Constants {8, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, NULL}, + // ShaderDebugBind::MathResult + {9, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT, NULL}, }); - CREATE_OBJECT(PipeLayout, DescSetLayout, sizeof(Vec4f) * 3 + sizeof(uint32_t)); + CREATE_OBJECT(PipeLayout, DescSetLayout, sizeof(Vec4f) * 6 + sizeof(uint32_t)); CREATE_OBJECT(DescSet, descriptorPool, DescSetLayout); @@ -4040,8 +4043,12 @@ void ShaderDebugData::Init(WrappedVulkan *driver, VkDescriptorPool descriptorPoo vkr = driver->vkCreateFramebuffer(driver->GetDev(), &fbinfo, NULL, &Framebuffer); RDCASSERTEQUAL(vkr, VK_SUCCESS); + MathResult.Create(driver, driver->GetDev(), sizeof(Vec4f) * 4, 1, + GPUBuffer::eGPUBufferGPULocal | GPUBuffer::eGPUBufferSSBO); + // don't need to ring this, as we hard-sync for readback anyway - ReadbackBuffer.Create(driver, driver->GetDev(), sizeof(Vec4f), 1, GPUBuffer::eGPUBufferReadback); + ReadbackBuffer.Create(driver, driver->GetDev(), sizeof(Vec4f) * 4, 1, + GPUBuffer::eGPUBufferReadback); ConstantsBuffer.Create(driver, driver->GetDev(), 1024, 1, 0); } @@ -4050,7 +4057,8 @@ void ShaderDebugData::Destroy(WrappedVulkan *driver) ConstantsBuffer.Destroy(); ReadbackBuffer.Destroy(); - driver->vkDestroyPipeline(driver->GetDev(), MathPipe, NULL); + for(size_t i = 0; i < ARRAY_COUNT(MathPipe); i++) + driver->vkDestroyPipeline(driver->GetDev(), MathPipe[i], NULL); driver->vkDestroyDescriptorSetLayout(driver->GetDev(), DescSetLayout, NULL); driver->vkDestroyPipelineLayout(driver->GetDev(), PipeLayout, NULL); @@ -4062,9 +4070,8 @@ void ShaderDebugData::Destroy(WrappedVulkan *driver) driver->vkDestroyRenderPass(driver->GetDev(), RenderPass, NULL); // one module each for float, uint, sint. - driver->vkDestroyShaderModule(driver->GetDev(), Module[0], NULL); - driver->vkDestroyShaderModule(driver->GetDev(), Module[1], NULL); - driver->vkDestroyShaderModule(driver->GetDev(), Module[2], NULL); + for(size_t i = 0; i < ARRAY_COUNT(Module); i++) + driver->vkDestroyShaderModule(driver->GetDev(), Module[i], NULL); for(auto it = m_Pipelines.begin(); it != m_Pipelines.end(); it++) driver->vkDestroyPipeline(driver->GetDev(), it->second, NULL); diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index 0ec4a77ea..02d42a834 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -225,7 +225,7 @@ struct ShaderDebugData VkPipelineLayout PipeLayout = VK_NULL_HANDLE; VkDescriptorSet DescSet = VK_NULL_HANDLE; - VkPipeline MathPipe = VK_NULL_HANDLE; + VkPipeline MathPipe[3] = {}; VkImage Image = VK_NULL_HANDLE; VkImageView ImageView = VK_NULL_HANDLE; @@ -236,10 +236,11 @@ struct ShaderDebugData VkDescriptorImageInfo DummyImageInfos[3][6] = {}; VkWriteDescriptorSet DummyWrites[3][7] = {}; - VkShaderModule Module[4] = {}; + VkShaderModule Module[6] = {}; std::map m_Pipelines; + GPUBuffer MathResult; GPUBuffer ConstantsBuffer; GPUBuffer ReadbackBuffer; }; diff --git a/renderdoc/driver/vulkan/vk_shaderdebug.cpp b/renderdoc/driver/vulkan/vk_shaderdebug.cpp index 76bf9b1d6..9849ed001 100644 --- a/renderdoc/driver/vulkan/vk_shaderdebug.cpp +++ b/renderdoc/driver/vulkan/vk_shaderdebug.cpp @@ -85,6 +85,7 @@ enum class ShaderDebugBind Sampler = 7, Constants = 8, Count, + MathResult = 9, }; struct Vec3i @@ -129,9 +130,9 @@ struct ShaderUniformParameters { Vec3i texel_uvw; int texel_lod; - Vec4f uvwa; - Vec3f ddx; - Vec3f ddy; + float uvwa[4]; + float ddx[3]; + float ddy[3]; Vec3i offset; int sampleIdx; float compare; @@ -630,21 +631,23 @@ public: uint32_t mip = viewProps.range.baseMipLevel; if(opcode == rdcspv::Op::ImageQuerySizeLod) - mip += lane.GetSrc(operands.lod).value.u.x; + mip += uintComp(lane.GetSrc(operands.lod), 0); + + RDCEraseEl(output.value); int i = 0; - output.value.uv[i++] = RDCMAX(1U, imageProps.extent.width >> mip); + setUintComp(output, i++, RDCMAX(1U, imageProps.extent.width >> mip)); if(coords >= 2) - output.value.uv[i++] = RDCMAX(1U, imageProps.extent.height >> mip); + setUintComp(output, i++, RDCMAX(1U, imageProps.extent.height >> mip)); if(viewProps.viewType == VK_IMAGE_VIEW_TYPE_3D) - output.value.uv[i++] = RDCMAX(1U, imageProps.extent.depth >> mip); + setUintComp(output, i++, RDCMAX(1U, imageProps.extent.depth >> mip)); if(viewProps.viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY || viewProps.viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY) - output.value.uv[i++] = imageProps.arrayLayers; + setUintComp(output, i++, imageProps.arrayLayers); else if(viewProps.viewType == VK_IMAGE_VIEW_TYPE_CUBE || viewProps.viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) - output.value.uv[i++] = imageProps.arrayLayers / 6; + setUintComp(output, i++, imageProps.arrayLayers / 6); if(buffer) { @@ -659,8 +662,7 @@ public: size = bufProps.size - bufViewProps.offset; } - output.value.uv[0] = uint32_t(size / GetByteSize(1, 1, 1, bufViewProps.format, 0)); - output.value.uv[1] = output.value.uv[2] = output.value.uv[3] = 0; + setUintComp(output, 0, uint32_t(size / GetByteSize(1, 1, 1, bufViewProps.format, 0))); } return true; @@ -703,7 +705,15 @@ public: if(operands.flags & rdcspv::ImageOperands::Bias) { - float bias = lane.GetSrc(operands.bias).value.f.x; + const ShaderVariable &biasVar = lane.GetSrc(operands.bias); + + float bias = biasVar.value.f.x; + // silently cast parameters to 32-bit floats + if(biasVar.type == VarType::Half) + bias = ConvertFromHalf(biasVar.value.u16v[0]); + else if(biasVar.type == VarType::Double) + bias = (float)biasVar.value.dv[0]; + if(bias != 0.0f) { // bias can only be used with implicit lod operations, but we want to do everything with @@ -847,32 +857,41 @@ public: { // co-ordinates after the used ones are read as 0s. This allows us to then read an implicit // 0 for array layer when we promote accesses to arrays. - uniformParams.texel_uvw.x = uv.value.u.x; + uniformParams.texel_uvw.x = uintComp(uv, 0); if(coords >= 2) - uniformParams.texel_uvw.y = uv.value.u.y; + uniformParams.texel_uvw.y = uintComp(uv, 1); if(coords >= 3) - uniformParams.texel_uvw.z = uv.value.u.z; + uniformParams.texel_uvw.z = uintComp(uv, 2); if(!buffer && operands.flags & rdcspv::ImageOperands::Lod) - uniformParams.texel_lod = lane.GetSrc(operands.lod).value.i.x; + uniformParams.texel_lod = uintComp(lane.GetSrc(operands.lod), 0); else uniformParams.texel_lod = 0; if(operands.flags & rdcspv::ImageOperands::Sample) - uniformParams.sampleIdx = lane.GetSrc(operands.sample).value.u.x; + uniformParams.sampleIdx = uintComp(lane.GetSrc(operands.sample), 0); break; } case rdcspv::Op::ImageGather: case rdcspv::Op::ImageDrefGather: { - uniformParams.uvwa.x = uv.value.f.x; - if(coords >= 2) - uniformParams.uvwa.y = uv.value.f.y; - if(coords >= 3) - uniformParams.uvwa.z = uv.value.f.z; - if(coords >= 4) - uniformParams.uvwa.z = uv.value.f.w; + // silently cast parameters to 32-bit floats + if(uv.type == VarType::Float) + { + for(int i = 0; i < coords; i++) + uniformParams.uvwa[i] = uv.value.fv[i]; + } + else if(uv.type == VarType::Half) + { + for(int i = 0; i < coords; i++) + uniformParams.uvwa[i] = ConvertFromHalf(uv.value.u16v[i]); + } + else if(uv.type == VarType::Double) + { + for(int i = 0; i < coords; i++) + uniformParams.uvwa[i] = (float)uv.value.dv[i]; + } if(useCompare) uniformParams.compare = compare.value.f.x; @@ -888,19 +907,44 @@ public: // should be an array of ivec2 RDCASSERT(constOffsets.members.size() == 4); + // sign extend variables lower than 32-bits + for(int i = 0; i < 4; i++) + { + if(constOffsets.members[i].type == VarType::SByte) + { + constOffsets.members[i].value.i.x = constOffsets.members[i].value.s8v[0]; + constOffsets.members[i].value.i.y = constOffsets.members[i].value.s8v[1]; + } + else if(constOffsets.members[i].type == VarType::SShort) + { + constOffsets.members[i].value.i.x = constOffsets.members[i].value.s16v[0]; + constOffsets.members[i].value.i.y = constOffsets.members[i].value.s16v[1]; + } + } + constParams.gatherOffsets.u0 = constOffsets.members[0].value.i.x; constParams.gatherOffsets.v0 = constOffsets.members[0].value.i.y; constParams.gatherOffsets.u1 = constOffsets.members[1].value.i.x; constParams.gatherOffsets.v1 = constOffsets.members[1].value.i.y; - constParams.gatherOffsets.u2 = constOffsets.members[1].value.i.x; - constParams.gatherOffsets.v2 = constOffsets.members[1].value.i.y; - constParams.gatherOffsets.u3 = constOffsets.members[1].value.i.x; - constParams.gatherOffsets.v3 = constOffsets.members[1].value.i.y; + constParams.gatherOffsets.u2 = constOffsets.members[2].value.i.x; + constParams.gatherOffsets.v2 = constOffsets.members[2].value.i.y; + constParams.gatherOffsets.u3 = constOffsets.members[3].value.i.x; + constParams.gatherOffsets.v3 = constOffsets.members[3].value.i.y; } if(operands.flags & rdcspv::ImageOperands::ConstOffset) { ShaderVariable constOffset = lane.GetSrc(operands.constOffset); + + // sign extend variables lower than 32-bits + for(uint8_t c = 0; c < constOffset.columns; c++) + { + if(constOffset.type == VarType::SByte) + constOffset.value.iv[c] = constOffset.value.s8v[c]; + else if(constOffset.type == VarType::SShort) + constOffset.value.iv[c] = constOffset.value.s16v[c]; + } + uniformParams.offset.x = constOffset.value.i.x; if(gradCoords >= 2) uniformParams.offset.y = constOffset.value.i.y; @@ -910,6 +954,16 @@ public: else if(operands.flags & rdcspv::ImageOperands::Offset) { ShaderVariable offset = lane.GetSrc(operands.offset); + + // sign extend variables lower than 32-bits + for(uint8_t c = 0; c < offset.columns; c++) + { + if(offset.type == VarType::SByte) + offset.value.iv[c] = offset.value.s8v[c]; + else if(offset.type == VarType::SShort) + offset.value.iv[c] = offset.value.s16v[c]; + } + uniformParams.offset.x = offset.value.i.x; if(gradCoords >= 2) uniformParams.offset.y = offset.value.i.y; @@ -929,13 +983,22 @@ public: case rdcspv::Op::ImageSampleProjDrefExplicitLod: case rdcspv::Op::ImageSampleProjDrefImplicitLod: { - uniformParams.uvwa.x = uv.value.f.x; - if(coords >= 2) - uniformParams.uvwa.y = uv.value.f.y; - if(coords >= 3) - uniformParams.uvwa.z = uv.value.f.z; - if(coords >= 4) - uniformParams.uvwa.w = uv.value.f.w; + // silently cast parameters to 32-bit floats + if(uv.type == VarType::Float) + { + for(int i = 0; i < coords; i++) + uniformParams.uvwa[i] = uv.value.fv[i]; + } + else if(uv.type == VarType::Half) + { + for(int i = 0; i < coords; i++) + uniformParams.uvwa[i] = ConvertFromHalf(uv.value.u16v[i]); + } + else if(uv.type == VarType::Double) + { + for(int i = 0; i < coords; i++) + uniformParams.uvwa[i] = (float)uv.value.dv[i]; + } if(proj) { @@ -946,20 +1009,48 @@ public: // do the divide ourselves rather than severely complicating the sample shader (as proj // variants need non-arrayed textures) float q = uv.value.fv[coords]; - uniformParams.uvwa.x /= q; - uniformParams.uvwa.y /= q; - uniformParams.uvwa.z /= q; + if(uv.type == VarType::Half) + q = ConvertFromHalf(uv.value.u16v[coords]); + else if(uv.type == VarType::Double) + q = (float)uv.value.dv[coords]; + + uniformParams.uvwa[0] /= q; + uniformParams.uvwa[1] /= q; + uniformParams.uvwa[2] /= q; } if(operands.flags & rdcspv::ImageOperands::MinLod) - uniformParams.minlod = lane.GetSrc(operands.minLod).value.f.x; + { + const ShaderVariable &minLodVar = lane.GetSrc(operands.minLod); + + uniformParams.minlod = minLodVar.value.f.x; + // silently cast parameters to 32-bit floats + if(minLodVar.type == VarType::Half) + uniformParams.minlod = ConvertFromHalf(minLodVar.value.u16v[0]); + else if(minLodVar.type == VarType::Double) + uniformParams.minlod = (float)minLodVar.value.dv[0]; + } if(useCompare) + { uniformParams.compare = compare.value.f.x; + // silently cast parameters to 32-bit floats + if(compare.type == VarType::Half) + uniformParams.compare = ConvertFromHalf(compare.value.u16v[0]); + else if(compare.type == VarType::Double) + uniformParams.compare = (float)compare.value.dv[0]; + } if(operands.flags & rdcspv::ImageOperands::Lod) { - uniformParams.lod = lane.GetSrc(operands.lod).value.f.x; + const ShaderVariable &lodVar = lane.GetSrc(operands.lod); + + uniformParams.lod = lodVar.value.f.x; + // silently cast parameters to 32-bit floats + if(lodVar.type == VarType::Half) + uniformParams.lod = ConvertFromHalf(lodVar.value.u16v[0]); + else if(lodVar.type == VarType::Double) + uniformParams.lod = (float)lodVar.value.dv[0]; constParams.useGradOrGatherOffsets = VK_FALSE; } else if(operands.flags & rdcspv::ImageOperands::Grad) @@ -969,17 +1060,32 @@ public: constParams.useGradOrGatherOffsets = VK_TRUE; - uniformParams.ddx.x = ddx.value.f.x; - if(gradCoords >= 2) - uniformParams.ddx.y = ddx.value.f.y; - if(gradCoords >= 3) - uniformParams.ddx.z = ddx.value.f.z; - - uniformParams.ddy.x = ddy.value.f.x; - if(gradCoords >= 2) - uniformParams.ddy.y = ddy.value.f.y; - if(gradCoords >= 3) - uniformParams.ddy.z = ddy.value.f.z; + // silently cast parameters to 32-bit floats + RDCASSERTEQUAL(ddx.type, ddy.type); + if(ddx.type == VarType::Float) + { + for(int i = 0; i < gradCoords; i++) + { + uniformParams.ddx[i] = ddx.value.fv[i]; + uniformParams.ddy[i] = ddy.value.fv[i]; + } + } + else if(ddx.type == VarType::Half) + { + for(int i = 0; i < gradCoords; i++) + { + uniformParams.ddx[i] = ConvertFromHalf(ddx.value.u16v[i]); + uniformParams.ddy[i] = ConvertFromHalf(ddy.value.u16v[i]); + } + } + else if(ddx.type == VarType::Double) + { + for(int i = 0; i < gradCoords; i++) + { + uniformParams.ddx[i] = (float)ddx.value.dv[i]; + uniformParams.ddy[i] = (float)ddy.value.dv[i]; + } + } } if(opcode == rdcspv::Op::ImageSampleImplicitLod || @@ -988,22 +1094,47 @@ public: // use grad to sub in for the implicit lod constParams.useGradOrGatherOffsets = VK_TRUE; - uniformParams.ddx.x = ddxCalc.value.f.x; - if(gradCoords >= 2) - uniformParams.ddx.y = ddxCalc.value.f.y; - if(gradCoords >= 3) - uniformParams.ddx.z = ddxCalc.value.f.z; - - uniformParams.ddy.x = ddyCalc.value.f.x; - if(gradCoords >= 2) - uniformParams.ddy.y = ddyCalc.value.f.y; - if(gradCoords >= 3) - uniformParams.ddy.z = ddyCalc.value.f.z; + // silently cast parameters to 32-bit floats + RDCASSERTEQUAL(ddxCalc.type, ddyCalc.type); + if(ddxCalc.type == VarType::Float) + { + for(int i = 0; i < gradCoords; i++) + { + uniformParams.ddx[i] = ddxCalc.value.fv[i]; + uniformParams.ddy[i] = ddyCalc.value.fv[i]; + } + } + else if(ddxCalc.type == VarType::Half) + { + for(int i = 0; i < gradCoords; i++) + { + uniformParams.ddx[i] = ConvertFromHalf(ddxCalc.value.u16v[i]); + uniformParams.ddy[i] = ConvertFromHalf(ddyCalc.value.u16v[i]); + } + } + else if(ddxCalc.type == VarType::Double) + { + for(int i = 0; i < gradCoords; i++) + { + uniformParams.ddx[i] = (float)ddxCalc.value.dv[i]; + uniformParams.ddy[i] = (float)ddyCalc.value.dv[i]; + } + } } if(operands.flags & rdcspv::ImageOperands::ConstOffset) { ShaderVariable constOffset = lane.GetSrc(operands.constOffset); + + // sign extend variables lower than 32-bits + for(uint8_t c = 0; c < constOffset.columns; c++) + { + if(constOffset.type == VarType::SByte) + constOffset.value.iv[c] = constOffset.value.s8v[c]; + else if(constOffset.type == VarType::SShort) + constOffset.value.iv[c] = constOffset.value.s16v[c]; + } + uniformParams.offset.x = constOffset.value.i.x; if(gradCoords >= 2) uniformParams.offset.y = constOffset.value.i.y; @@ -1013,6 +1144,16 @@ public: else if(operands.flags & rdcspv::ImageOperands::Offset) { ShaderVariable offset = lane.GetSrc(operands.offset); + + // sign extend variables lower than 32-bits + for(uint8_t c = 0; c < offset.columns; c++) + { + if(offset.type == VarType::SByte) + offset.value.iv[c] = offset.value.s8v[c]; + else if(offset.type == VarType::SShort) + offset.value.iv[c] = offset.value.s16v[c]; + } + uniformParams.offset.x = offset.value.i.x; if(gradCoords >= 2) uniformParams.offset.y = offset.value.i.y; @@ -1043,7 +1184,7 @@ public: uniformParams.offset.x, uniformParams.offset.y, uniformParams.offset.z)); } - VkPipeline pipe = MakePipe(constParams, uintTex, sintTex); + VkPipeline pipe = MakePipe(constParams, 32, uintTex, sintTex); if(pipe == VK_NULL_HANDLE) { @@ -1171,9 +1312,23 @@ public: m_pDriver->FlushQ(); } - Vec4f *ret = (Vec4f *)m_DebugData.ReadbackBuffer.Map(NULL, 0); + float *ret = (float *)m_DebugData.ReadbackBuffer.Map(NULL, 0); - memcpy(output.value.uv, ret, sizeof(Vec4f)); + // convert float results, we did all sampling at 32-bit precision + if(output.type == VarType::Half) + { + for(uint8_t c = 0; c < 4; c++) + output.value.u16v[c] = ConvertToHalf(ret[c]); + } + else if(output.type == VarType::Double) + { + for(uint8_t c = 0; c < 4; c++) + output.value.dv[c] = ret[c]; + } + else + { + memcpy(output.value.uv, ret, sizeof(Vec4f)); + } m_DebugData.ReadbackBuffer.Unmap(); @@ -1185,13 +1340,20 @@ public: { RDCASSERT(params.size() <= 3, params.size()); - if(m_DebugData.MathPipe == VK_NULL_HANDLE) + int floatSizeIdx = 0; + if(params[0].type == VarType::Half) + floatSizeIdx = 1; + else if(params[0].type == VarType::Double) + floatSizeIdx = 2; + + if(m_DebugData.MathPipe[floatSizeIdx] == VK_NULL_HANDLE) { ShaderConstParameters pipeParams = {}; pipeParams.operation = (uint32_t)rdcspv::Op::ExtInst; - m_DebugData.MathPipe = MakePipe(pipeParams, false, false); + m_DebugData.MathPipe[floatSizeIdx] = + MakePipe(pipeParams, VarTypeByteSize(params[0].type) * 8, false, false); - if(m_DebugData.MathPipe == VK_NULL_HANDLE) + if(m_DebugData.MathPipe[floatSizeIdx] == VK_NULL_HANDLE) { m_pDriver->AddDebugMessage(MessageCategory::Execution, MessageSeverity::High, MessageSource::RuntimeWarning, @@ -1200,6 +1362,21 @@ public: } } + VkDescriptorBufferInfo storageWriteInfo = {}; + m_DebugData.MathResult.FillDescriptor(storageWriteInfo); + + VkWriteDescriptorSet writeSets[] = { + { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_DebugData.DescSet), + (uint32_t)ShaderDebugBind::MathResult, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, NULL, + &storageWriteInfo, NULL, + }, + }; + + VkDevice dev = m_pDriver->GetDev(); + + ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), 1, writeSets, 0, NULL); + { VkCommandBuffer cmd = m_pDriver->GetNextCmd(); @@ -1209,59 +1386,52 @@ public: VkResult vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); RDCASSERTEQUAL(vkr, VK_SUCCESS); - VkClearValue clear = {}; + ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, + Unwrap(m_DebugData.MathPipe[floatSizeIdx])); - VkRenderPassBeginInfo rpbegin = { - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - NULL, - Unwrap(m_DebugData.RenderPass), - Unwrap(m_DebugData.Framebuffer), - {{0, 0}, {1, 1}}, - 1, - &clear, - }; - ObjDisp(cmd)->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); - - ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(m_DebugData.MathPipe)); + ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, + Unwrap(m_DebugData.PipeLayout), 0, 1, + UnwrapPtr(m_DebugData.DescSet), 0, NULL); // push the parameters for(size_t i = 0; i < params.size(); i++) { - float p[4] = {}; - memcpy(p, params[i].value.fv, sizeof(float) * params[i].columns); + RDCASSERTEQUAL(params[i].type, params[0].type); + double p[4] = {}; + memcpy(p, params[i].value.fv, VarTypeByteSize(params[i].type) * params[i].columns); ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_DebugData.PipeLayout), - VK_SHADER_STAGE_ALL, uint32_t(sizeof(Vec4f) * i), - sizeof(Vec4f), p); + VK_SHADER_STAGE_ALL, uint32_t(sizeof(p) * i), sizeof(p), p); } // push the operation afterwards ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_DebugData.PipeLayout), - VK_SHADER_STAGE_ALL, sizeof(Vec4f) * 3, sizeof(uint32_t), &op); + VK_SHADER_STAGE_ALL, sizeof(Vec4f) * 6, sizeof(uint32_t), &op); - ObjDisp(cmd)->CmdDraw(Unwrap(cmd), 3, 1, 0, 0); - - ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd)); - - VkBufferImageCopy region = { - 0, sizeof(Vec4f), 1, {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, {0, 0, 0}, {1, 1, 1}, - }; - ObjDisp(cmd)->CmdCopyImageToBuffer(Unwrap(cmd), Unwrap(m_DebugData.Image), - VK_IMAGE_LAYOUT_GENERAL, - Unwrap(m_DebugData.ReadbackBuffer.buf), 1, ®ion); + ObjDisp(cmd)->CmdDispatch(Unwrap(cmd), 1, 1, 1); VkBufferMemoryBarrier bufBarrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, NULL, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_HOST_READ_BIT, + VK_ACCESS_SHADER_WRITE_BIT, + VK_ACCESS_TRANSFER_READ_BIT, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, - Unwrap(m_DebugData.ReadbackBuffer.buf), + Unwrap(m_DebugData.MathResult.buf), 0, VK_WHOLE_SIZE, }; + DoPipelineBarrier(cmd, 1, &bufBarrier); + + VkBufferCopy bufCopy = {0, 0, 0}; + bufCopy.size = sizeof(Vec4f) * 2; + ObjDisp(cmd)->CmdCopyBuffer(Unwrap(cmd), Unwrap(m_DebugData.MathResult.buf), + Unwrap(m_DebugData.ReadbackBuffer.buf), 1, &bufCopy); + + bufBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + bufBarrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT; + bufBarrier.buffer = Unwrap(m_DebugData.ReadbackBuffer.buf); + // wait for copy to finish before reading back to host DoPipelineBarrier(cmd, 1, &bufBarrier); @@ -1272,16 +1442,16 @@ public: m_pDriver->FlushQ(); } - Vec4f *ret = (Vec4f *)m_DebugData.ReadbackBuffer.Map(NULL, 0); - - memcpy(output.value.uv, ret, sizeof(Vec4f)); - - m_DebugData.ReadbackBuffer.Unmap(); + byte *ret = (byte *)m_DebugData.ReadbackBuffer.Map(NULL, 0); // these two operations change the type of the output if(op == rdcspv::GLSLstd450::Length || op == rdcspv::GLSLstd450::Distance) output.columns = 1; + memcpy(output.value.uv, ret, VarTypeByteSize(output.type) * output.columns); + + m_DebugData.ReadbackBuffer.Unmap(); + return true; } @@ -1511,7 +1681,8 @@ private: return data; } - VkPipeline MakePipe(const ShaderConstParameters ¶ms, bool uintTex, bool sintTex) + VkPipeline MakePipe(const ShaderConstParameters ¶ms, uint32_t floatBitSize, bool uintTex, + bool sintTex) { VkSpecializationMapEntry specMaps[sizeof(params) / sizeof(uint32_t)]; for(size_t i = 0; i < ARRAY_COUNT(specMaps); i++) @@ -1534,16 +1705,28 @@ private: shaderIndex = 2; if(params.operation == (uint32_t)rdcspv::Op::ExtInst) + { shaderIndex = 3; + if(floatBitSize == 16) + shaderIndex = 4; + else if(floatBitSize == 64) + shaderIndex = 5; + } if(m_DebugData.Module[shaderIndex] == VK_NULL_HANDLE) { rdcarray spirv; - if(shaderIndex == 3) - GenerateMathShaderModule(spirv); + if(params.operation == (uint32_t)rdcspv::Op::ExtInst) + { + GenerateMathShaderModule(spirv, floatBitSize); + } else + { + RDCASSERTMSG("Assume sampling happens with 32-bit float inputs", floatBitSize == 32, + floatBitSize); GenerateSamplingShaderModule(spirv, uintTex, sintTex); + } VkShaderModuleCreateInfo moduleCreateInfo = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; moduleCreateInfo.pCode = spirv.data(); @@ -1555,7 +1738,7 @@ private: const char *filename[] = { "/debug_psgather_float.spv", "/debug_psgather_uint.spv", "/debug_psgather_sint.spv", - "/debug_psmath.spv", + "/debug_psmath32.spv", "/debug_psmath16.spv", "/debug_psmath64.spv", }; if(!Vulkan_Debug_PSDebugDumpDirPath().empty()) @@ -1573,6 +1756,34 @@ private: shaderIndex, ToStr((rdcspv::Op)params.operation).c_str(), params.dim, params.useGradOrGatherOffsets, params.gatherChannel); + if(params.operation == (uint32_t)rdcspv::Op::ExtInst) + { + VkComputePipelineCreateInfo computePipeInfo = { + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + NULL, + 0, + {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, + VK_SHADER_STAGE_COMPUTE_BIT, m_DebugData.Module[shaderIndex], "main", NULL}, + m_DebugData.PipeLayout, + VK_NULL_HANDLE, + 0, + }; + + VkPipeline pipe = VK_NULL_HANDLE; + VkResult vkr = m_pDriver->vkCreateComputePipelines(m_pDriver->GetDev(), + m_pDriver->GetShaderCache()->GetPipeCache(), + 1, &computePipeInfo, NULL, &pipe); + if(vkr != VK_SUCCESS) + { + RDCERR("Failed creating debug pipeline: %s", ToStr(vkr).c_str()); + return VK_NULL_HANDLE; + } + + m_DebugData.m_Pipelines[key] = pipe; + + return pipe; + } + const VkPipelineShaderStageCreateInfo shaderStages[2] = { {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_VERTEX_BIT, m_pDriver->GetShaderCache()->GetBuiltinModule(BuiltinShader::ShaderDebugSampleVS), "main", @@ -1672,7 +1883,7 @@ private: return pipe; } - void GenerateMathShaderModule(rdcarray &spirv) + void GenerateMathShaderModule(rdcarray &spirv, uint32_t floatBitSize) { rdcspv::Editor editor(spirv); @@ -1689,21 +1900,29 @@ private: rdcspv::Id glsl450 = editor.ImportExtInst("GLSL.std.450"); + rdcspv::Scalar sizedScalar; + if(floatBitSize == 32) + sizedScalar = rdcspv::scalar(); + else if(floatBitSize == 64) + sizedScalar = rdcspv::scalar(); + else + sizedScalar = rdcspv::scalar(); + rdcspv::Id u32 = editor.DeclareType(rdcspv::scalar()); - rdcspv::Id f32 = editor.DeclareType(rdcspv::scalar()); - rdcspv::Id v4f32 = editor.DeclareType(rdcspv::Vector(rdcspv::scalar(), 4)); + rdcspv::Id floatType = editor.DeclareType(sizedScalar); + rdcspv::Id vec4Type = editor.DeclareType(rdcspv::Vector(sizedScalar, 4)); rdcspv::Id pushStructID = - editor.AddType(rdcspv::OpTypeStruct(editor.MakeId(), {v4f32, v4f32, v4f32, u32})); + editor.AddType(rdcspv::OpTypeStruct(editor.MakeId(), {vec4Type, vec4Type, vec4Type, u32})); editor.AddDecoration(rdcspv::OpDecorate(pushStructID, rdcspv::Decoration::Block)); editor.AddDecoration(rdcspv::OpMemberDecorate( pushStructID, 0, rdcspv::DecorationParam(0))); editor.AddDecoration(rdcspv::OpMemberDecorate( - pushStructID, 1, rdcspv::DecorationParam(sizeof(Vec4f)))); + pushStructID, 1, rdcspv::DecorationParam(sizeof(Vec4f) * 2))); editor.AddDecoration(rdcspv::OpMemberDecorate( - pushStructID, 2, rdcspv::DecorationParam(sizeof(Vec4f) * 2))); + pushStructID, 2, rdcspv::DecorationParam(sizeof(Vec4f) * 4))); editor.AddDecoration(rdcspv::OpMemberDecorate( - pushStructID, 3, rdcspv::DecorationParam(sizeof(Vec4f) * 3))); + pushStructID, 3, rdcspv::DecorationParam(sizeof(Vec4f) * 6))); editor.SetMemberName(pushStructID, 0, "a"); editor.SetMemberName(pushStructID, 1, "b"); editor.SetMemberName(pushStructID, 2, "c"); @@ -1715,24 +1934,35 @@ private: rdcspv::OpVariable(pushPtrType, editor.MakeId(), rdcspv::StorageClass::PushConstant)); editor.SetName(pushVar, "pushData"); - rdcspv::Id pushv4f32Type = - editor.DeclareType(rdcspv::Pointer(v4f32, rdcspv::StorageClass::PushConstant)); + rdcspv::Id pushv4Type = + editor.DeclareType(rdcspv::Pointer(vec4Type, rdcspv::StorageClass::PushConstant)); rdcspv::Id pushu32Type = editor.DeclareType(rdcspv::Pointer(u32, rdcspv::StorageClass::PushConstant)); - rdcspv::Id outPtrType = editor.DeclareType(rdcspv::Pointer(v4f32, rdcspv::StorageClass::Output)); + rdcspv::Id storageStructType = editor.AddType(rdcspv::OpTypeStruct(editor.MakeId(), {vec4Type})); - rdcspv::Id outVar = editor.AddVariable( - rdcspv::OpVariable(outPtrType, editor.MakeId(), rdcspv::StorageClass::Output)); - editor.AddDecoration( - rdcspv::OpDecorate(outVar, rdcspv::DecorationParam(0))); + rdcspv::Id storageStructPtrType = + editor.DeclareType(rdcspv::Pointer(storageStructType, editor.StorageBufferClass())); + rdcspv::Id storageVec4PtrType = + editor.DeclareType(rdcspv::Pointer(vec4Type, editor.StorageBufferClass())); - editor.SetName(outVar, "output"); + rdcspv::Id storageVar = editor.AddVariable( + rdcspv::OpVariable(storageStructPtrType, editor.MakeId(), editor.StorageBufferClass())); + editor.AddDecoration(rdcspv::OpDecorate( + storageVar, rdcspv::DecorationParam(0U))); + editor.AddDecoration(rdcspv::OpDecorate( + storageVar, + rdcspv::DecorationParam((uint32_t)ShaderDebugBind::MathResult))); + editor.DecorateStorageBufferStruct(storageVar); + + editor.SetName(storageVar, "resultStorage"); // register the entry point - editor.AddOperation( - editor.Begin(rdcspv::Section::EntryPoints), - rdcspv::OpEntryPoint(rdcspv::ExecutionModel::Fragment, entryId, "main", {outVar})); + editor.AddOperation(editor.Begin(rdcspv::Section::EntryPoints), + rdcspv::OpEntryPoint(rdcspv::ExecutionModel::GLCompute, entryId, "main", {})); + editor.AddExecutionMode(rdcspv::OpExecutionMode( + entryId, rdcspv::ExecutionModeParam(1, 1, 1))); + editor.AddOperation(editor.Begin(rdcspv::Section::ExecutionMode), rdcspv::OpExecutionMode(entryId, rdcspv::ExecutionMode::OriginUpperLeft)); @@ -1748,20 +1978,32 @@ private: editor.AddConstantImmediate(2), editor.AddConstantImmediate(3), }; + rdcspv::Id zerof; + if(floatBitSize == 32) + zerof = editor.AddConstantImmediate(0.0f); + else if(floatBitSize == 64) + zerof = editor.AddConstantImmediate(0.0); + else + zerof = editor.AddConstantImmediate(half_float::half(0.0f)); + // load the parameters and the op rdcspv::Id aPtr = - func.add(rdcspv::OpAccessChain(pushv4f32Type, editor.MakeId(), pushVar, {consts[0]})); + func.add(rdcspv::OpAccessChain(pushv4Type, editor.MakeId(), pushVar, {consts[0]})); rdcspv::Id bPtr = - func.add(rdcspv::OpAccessChain(pushv4f32Type, editor.MakeId(), pushVar, {consts[1]})); + func.add(rdcspv::OpAccessChain(pushv4Type, editor.MakeId(), pushVar, {consts[1]})); rdcspv::Id cPtr = - func.add(rdcspv::OpAccessChain(pushv4f32Type, editor.MakeId(), pushVar, {consts[2]})); + func.add(rdcspv::OpAccessChain(pushv4Type, editor.MakeId(), pushVar, {consts[2]})); rdcspv::Id opPtr = func.add(rdcspv::OpAccessChain(pushu32Type, editor.MakeId(), pushVar, {consts[3]})); - rdcspv::Id a = func.add(rdcspv::OpLoad(v4f32, editor.MakeId(), aPtr)); - rdcspv::Id b = func.add(rdcspv::OpLoad(v4f32, editor.MakeId(), bPtr)); - rdcspv::Id c = func.add(rdcspv::OpLoad(v4f32, editor.MakeId(), cPtr)); + rdcspv::Id a = func.add(rdcspv::OpLoad(vec4Type, editor.MakeId(), aPtr)); + rdcspv::Id b = func.add(rdcspv::OpLoad(vec4Type, editor.MakeId(), bPtr)); + rdcspv::Id c = func.add(rdcspv::OpLoad(vec4Type, editor.MakeId(), cPtr)); rdcspv::Id opParam = func.add(rdcspv::OpLoad(u32, editor.MakeId(), opPtr)); + // access chain the output + rdcspv::Id outVar = + func.add(rdcspv::OpAccessChain(storageVec4PtrType, editor.MakeId(), storageVar, {consts[0]})); + rdcspv::Id breakLabel = editor.MakeId(); rdcspv::Id defaultLabel = editor.MakeId(); @@ -1783,29 +2025,36 @@ private: rdcspv::GLSLstd450::Normalize, }) { + // most operations aren't allowed on doubles + if(floatBitSize == 64 && op != rdcspv::GLSLstd450::Sqrt && + op != rdcspv::GLSLstd450::InverseSqrt && op != rdcspv::GLSLstd450::Normalize) + continue; + rdcspv::Id label = editor.MakeId(); targets.push_back({(uint32_t)op, label}); cases.add(rdcspv::OpLabel(label)); - rdcspv::Id result = cases.add(rdcspv::OpGLSL450(v4f32, editor.MakeId(), glsl450, op, {a})); + rdcspv::Id result = cases.add(rdcspv::OpGLSL450(vec4Type, editor.MakeId(), glsl450, op, {a})); cases.add(rdcspv::OpStore(outVar, result)); cases.add(rdcspv::OpBranch(breakLabel)); } - // these take two parameters, but are otherwise identical - for(rdcspv::GLSLstd450 op : {rdcspv::GLSLstd450::Atan2, rdcspv::GLSLstd450::Pow}) + if(floatBitSize != 64) { - rdcspv::Id label = editor.MakeId(); - targets.push_back({(uint32_t)op, label}); + // these take two parameters, but are otherwise identical + for(rdcspv::GLSLstd450 op : {rdcspv::GLSLstd450::Atan2, rdcspv::GLSLstd450::Pow}) + { + rdcspv::Id label = editor.MakeId(); + targets.push_back({(uint32_t)op, label}); - cases.add(rdcspv::OpLabel(label)); - rdcspv::Id result = cases.add(rdcspv::OpGLSL450(v4f32, editor.MakeId(), glsl450, op, {a, b})); - cases.add(rdcspv::OpStore(outVar, result)); - cases.add(rdcspv::OpBranch(breakLabel)); + cases.add(rdcspv::OpLabel(label)); + rdcspv::Id result = + cases.add(rdcspv::OpGLSL450(vec4Type, editor.MakeId(), glsl450, op, {a, b})); + cases.add(rdcspv::OpStore(outVar, result)); + cases.add(rdcspv::OpBranch(breakLabel)); + } } - rdcspv::Id zerof = editor.AddConstantImmediate(0.0f); - { rdcspv::GLSLstd450 op = rdcspv::GLSLstd450::Fma; @@ -1814,7 +2063,7 @@ private: cases.add(rdcspv::OpLabel(label)); rdcspv::Id result = - cases.add(rdcspv::OpGLSL450(v4f32, editor.MakeId(), glsl450, op, {a, b, c})); + cases.add(rdcspv::OpGLSL450(vec4Type, editor.MakeId(), glsl450, op, {a, b, c})); cases.add(rdcspv::OpStore(outVar, result)); cases.add(rdcspv::OpBranch(breakLabel)); } @@ -1827,9 +2076,9 @@ private: targets.push_back({(uint32_t)op, label}); cases.add(rdcspv::OpLabel(label)); - rdcspv::Id result = cases.add(rdcspv::OpGLSL450(f32, editor.MakeId(), glsl450, op, {a})); + rdcspv::Id result = cases.add(rdcspv::OpGLSL450(floatType, editor.MakeId(), glsl450, op, {a})); rdcspv::Id resultvec = cases.add( - rdcspv::OpCompositeConstruct(v4f32, editor.MakeId(), {result, zerof, zerof, zerof})); + rdcspv::OpCompositeConstruct(vec4Type, editor.MakeId(), {result, zerof, zerof, zerof})); cases.add(rdcspv::OpStore(outVar, resultvec)); cases.add(rdcspv::OpBranch(breakLabel)); } @@ -1841,9 +2090,10 @@ private: targets.push_back({(uint32_t)op, label}); cases.add(rdcspv::OpLabel(label)); - rdcspv::Id result = cases.add(rdcspv::OpGLSL450(f32, editor.MakeId(), glsl450, op, {a, b})); + rdcspv::Id result = + cases.add(rdcspv::OpGLSL450(floatType, editor.MakeId(), glsl450, op, {a, b})); rdcspv::Id resultvec = cases.add( - rdcspv::OpCompositeConstruct(v4f32, editor.MakeId(), {result, zerof, zerof, zerof})); + rdcspv::OpCompositeConstruct(vec4Type, editor.MakeId(), {result, zerof, zerof, zerof})); cases.add(rdcspv::OpStore(outVar, resultvec)); cases.add(rdcspv::OpBranch(breakLabel)); } @@ -1855,9 +2105,9 @@ private: targets.push_back({(uint32_t)op, label}); cases.add(rdcspv::OpLabel(label)); - rdcspv::Id eta = cases.add(rdcspv::OpCompositeExtract(f32, editor.MakeId(), c, {0})); + rdcspv::Id eta = cases.add(rdcspv::OpCompositeExtract(floatType, editor.MakeId(), c, {0})); rdcspv::Id result = - cases.add(rdcspv::OpGLSL450(v4f32, editor.MakeId(), glsl450, op, {a, b, eta})); + cases.add(rdcspv::OpGLSL450(vec4Type, editor.MakeId(), glsl450, op, {a, b, eta})); cases.add(rdcspv::OpStore(outVar, result)); cases.add(rdcspv::OpBranch(breakLabel)); } @@ -1869,8 +2119,8 @@ private: // default: store NULL data func.add(rdcspv::OpLabel(defaultLabel)); - func.add(rdcspv::OpStore(outVar, - editor.AddConstant(rdcspv::OpConstantNull(v4f32, editor.MakeId())))); + func.add(rdcspv::OpStore( + outVar, editor.AddConstant(rdcspv::OpConstantNull(vec4Type, editor.MakeId())))); func.add(rdcspv::OpBranch(breakLabel)); func.add(rdcspv::OpLabel(breakLabel)); @@ -1982,16 +2232,16 @@ private: DECL_UNIFORM(int32_t, texel_v, texel_uvw.y); DECL_UNIFORM(int32_t, texel_w, texel_uvw.z); DECL_UNIFORM(int32_t, texel_lod, texel_lod); - DECL_UNIFORM(float, u, uvwa.x); - DECL_UNIFORM(float, v, uvwa.y); - DECL_UNIFORM(float, w, uvwa.z); - DECL_UNIFORM(float, cube_a, uvwa.w); - DECL_UNIFORM(float, dudx, ddx.x); - DECL_UNIFORM(float, dvdx, ddx.y); - DECL_UNIFORM(float, dwdx, ddx.z); - DECL_UNIFORM(float, dudy, ddy.x); - DECL_UNIFORM(float, dvdy, ddy.y); - DECL_UNIFORM(float, dwdy, ddy.z); + DECL_UNIFORM(float, u, uvwa[0]); + DECL_UNIFORM(float, v, uvwa[1]); + DECL_UNIFORM(float, w, uvwa[2]); + DECL_UNIFORM(float, cube_a, uvwa[3]); + DECL_UNIFORM(float, dudx, ddx[0]); + DECL_UNIFORM(float, dvdx, ddx[1]); + DECL_UNIFORM(float, dwdx, ddx[2]); + DECL_UNIFORM(float, dudy, ddy[0]); + DECL_UNIFORM(float, dvdy, ddy[1]); + DECL_UNIFORM(float, dwdy, ddy[2]); DECL_UNIFORM(int32_t, offset_x, offset.x); DECL_UNIFORM(int32_t, offset_y, offset.y); DECL_UNIFORM(int32_t, offset_z, offset.z); @@ -2100,8 +2350,7 @@ private: editor.AddOperation(editor.Begin(rdcspv::Section::EntryPoints), rdcspv::OpEntryPoint(rdcspv::ExecutionModel::Fragment, entryId, "main", {input_uvwa_var, outVar})); - editor.AddOperation(editor.Begin(rdcspv::Section::ExecutionMode), - rdcspv::OpExecutionMode(entryId, rdcspv::ExecutionMode::OriginUpperLeft)); + editor.AddExecutionMode(rdcspv::OpExecutionMode(entryId, rdcspv::ExecutionMode::OriginUpperLeft)); rdcspv::Id voidType = editor.DeclareType(rdcspv::scalar()); rdcspv::Id funcType = editor.DeclareType(rdcspv::FunctionType(voidType, {}));