diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index 5a644d020..808266e37 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -1242,7 +1242,8 @@ struct ShaderResource bool operator==(const ShaderResource &o) const { return resType == o.resType && name == o.name && variableType == o.variableType && - bindPoint == o.bindPoint && isTexture == o.isTexture && isReadOnly == o.isReadOnly; + bindPoint == o.bindPoint && isTexture == o.isTexture && hasSampler == o.hasSampler && + isReadOnly == o.isReadOnly; } bool operator<(const ShaderResource &o) const { @@ -1256,6 +1257,8 @@ struct ShaderResource return bindPoint < o.bindPoint; if(!(isTexture == o.isTexture)) return isTexture < o.isTexture; + if(!(hasSampler == o.hasSampler)) + return hasSampler < o.hasSampler; if(!(isReadOnly == o.isReadOnly)) return isReadOnly < o.isReadOnly; return false; @@ -1280,6 +1283,8 @@ struct ShaderResource DOCUMENT("``True`` if this resource is a texture, otherwise it is a buffer."); bool isTexture; + DOCUMENT("``True`` if this texture resource has a sampler as well."); + bool hasSampler = false; DOCUMENT(R"(``True`` if this resource is available to the shader for reading only, otherwise it is able to be read from and written to arbitrarily. )"); diff --git a/renderdoc/driver/gl/gl_shader_refl.cpp b/renderdoc/driver/gl/gl_shader_refl.cpp index 2ef7cbf5a..60c3742e7 100644 --- a/renderdoc/driver/gl/gl_shader_refl.cpp +++ b/renderdoc/driver/gl/gl_shader_refl.cpp @@ -1757,6 +1757,8 @@ void MakeShaderReflection(GLenum shadType, GLuint sepProg, ShaderReflection &ref continue; } + res.hasSampler = res.isReadOnly; + char *namebuf = new char[values[1] + 1]; GL.glGetProgramResourceName(sepProg, eGL_UNIFORM, u, values[1], NULL, namebuf); namebuf[values[1]] = 0; diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp index 961ddd1ab..6399acd0b 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp @@ -1437,7 +1437,10 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st Id imageTypeId = varType->id; if(varType->type == DataType::SampledImageType) + { imageTypeId = sampledImageTypes[varType->id].baseId; + res.hasSampler = true; + } const Image &imageType = imageTypes[imageTypeId]; diff --git a/renderdoc/driver/vulkan/vk_common.cpp b/renderdoc/driver/vulkan/vk_common.cpp index 5d5bebca8..fd8fba01f 100644 --- a/renderdoc/driver/vulkan/vk_common.cpp +++ b/renderdoc/driver/vulkan/vk_common.cpp @@ -566,6 +566,8 @@ VkShaderStageFlags ShaderMaskFromIndex(size_t index) VK_SHADER_STAGE_MESH_BIT_EXT, }; + RDCCOMPILE_ASSERT(ARRAY_COUNT(mask) == NumShaderStages, "Array is out of date"); + if(index < ARRAY_COUNT(mask)) return mask[index]; diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index b46f1fb05..3eda42658 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -817,6 +817,111 @@ bool CreateDescriptorWritesForSlotData(WrappedVulkan *vk, rdcarray &staticDescriptorAccess, + rdcarray setLayoutInfos) const +{ + if(!refl) + return; + + DescriptorAccess access; + access.stage = refl->stage; + + // we will store the descriptor set in byteSize to be decoded into descriptorStore later + access.byteSize = 0; + + staticDescriptorAccess.reserve(staticDescriptorAccess.size() + mapping->constantBlocks.size() + + mapping->samplers.size() + mapping->readOnlyResources.size() + + mapping->readWriteResources.size()); + + RDCASSERT(mapping->constantBlocks.size() < 0xffff, mapping->constantBlocks.size()); + for(uint16_t i = 0; i < mapping->constantBlocks.size(); i++) + { + const Bindpoint &bind = mapping->constantBlocks[i]; + // arrayed descriptors will be handled with bindless feedback + if(bind.arraySize > 1) + continue; + + access.staticallyUnused = !bind.used; + access.type = DescriptorType::ConstantBuffer; + access.index = i; + + if(bind.bindset == PushConstantBindSet) + { + access.byteSize = bind.bindset; + access.byteOffset = 0; + staticDescriptorAccess.push_back(access); + } + else if(bind.bindset == SpecializationConstantBindSet) + { + access.byteSize = bind.bindset; + access.byteOffset = 0; + staticDescriptorAccess.push_back(access); + } + else + { + access.byteSize = bind.bindset; + access.byteOffset = setLayoutInfos[bind.bindset]->bindings[bind.bind].elemOffset; + staticDescriptorAccess.push_back(access); + } + } + + RDCASSERT(mapping->samplers.size() < 0xffff, mapping->samplers.size()); + for(uint16_t i = 0; i < mapping->samplers.size(); i++) + { + const Bindpoint &bind = mapping->samplers[i]; + // arrayed descriptors will be handled with bindless feedback + if(bind.arraySize > 1) + continue; + + access.staticallyUnused = !bind.used; + access.type = DescriptorType::Sampler; + access.index = i; + access.byteSize = bind.bindset; + access.byteOffset = setLayoutInfos[bind.bindset]->bindings[bind.bind].elemOffset; + staticDescriptorAccess.push_back(access); + } + + RDCASSERT(mapping->readOnlyResources.size() < 0xffff, mapping->readOnlyResources.size()); + for(uint16_t i = 0; i < mapping->readOnlyResources.size(); i++) + { + const Bindpoint &bind = mapping->readOnlyResources[i]; + // arrayed descriptors will be handled with bindless feedback + if(bind.arraySize > 1) + continue; + + access.staticallyUnused = !bind.used; + access.type = DescriptorType::Image; + if(!refl->readOnlyResources[i].isTexture) + access.type = DescriptorType::TypedBuffer; + if(refl->readOnlyResources[i].hasSampler) + access.type = DescriptorType::ImageSampler; + access.index = i; + access.byteSize = bind.bindset; + access.byteOffset = setLayoutInfos[bind.bindset]->bindings[bind.bind].elemOffset; + staticDescriptorAccess.push_back(access); + } + + RDCASSERT(mapping->readWriteResources.size() < 0xffff, mapping->readWriteResources.size()); + for(uint16_t i = 0; i < mapping->readWriteResources.size(); i++) + { + const Bindpoint &bind = mapping->readWriteResources[i]; + // arrayed descriptors will be handled with bindless feedback + if(bind.arraySize > 1) + continue; + + access.staticallyUnused = !bind.used; + access.type = DescriptorType::ReadWriteImage; + if(!refl->readWriteResources[i].isTexture) + access.type = DescriptorType::ReadWriteBuffer; + + access.index = i; + access.byteSize = bind.bindset; + access.byteOffset = setLayoutInfos[bind.bindset]->bindings[bind.bind].elemOffset; + staticDescriptorAccess.push_back(access); + } +} + void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, ResourceId id, const VkGraphicsPipelineCreateInfo *pCreateInfo) @@ -1487,6 +1592,13 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, } } } + + rdcarray setLayoutInfos; + for(ResourceId setLayout : descSetLayouts) + setLayoutInfos.push_back(&info.m_DescSetLayout[setLayout]); + + for(const Shader &shad : shaders) + shad.ProcessStaticDescriptorAccess(staticDescriptorAccess, setLayoutInfos); } void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, @@ -1585,6 +1697,13 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, Vulk alphaToCoverageEnable = false; logicOpEnable = false; logicOp = VK_LOGIC_OP_NO_OP; + + rdcarray setLayoutInfos; + for(ResourceId setLayout : descSetLayouts) + setLayoutInfos.push_back(&info.m_DescSetLayout[setLayout]); + + for(const Shader &shad : shaders) + shad.ProcessStaticDescriptorAccess(staticDescriptorAccess, setLayoutInfos); } void VulkanCreationInfo::PipelineLayout::Init(VulkanResourceManager *resourceMan, diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index 2276d5073..58c9deeed 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -275,9 +275,14 @@ struct VulkanCreationInfo // VkPipelineShaderStageRequiredSubgroupSizeCreateInfo uint32_t requiredSubgroupSize = 0; + + void ProcessStaticDescriptorAccess(rdcarray &staticDescriptorAccess, + rdcarray setLayoutInfos) const; }; Shader shaders[NumShaderStages]; + rdcarray staticDescriptorAccess; + // VkPipelineVertexInputStateCreateInfo struct VertBinding { diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index fbaf911ee..dd4cf5735 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -2607,7 +2607,46 @@ rdcarray VulkanReplay::GetSamplerDescriptors(ResourceId descr rdcarray VulkanReplay::GetDescriptorAccess() { - return {}; + VulkanResourceManager *rm = m_pDriver->GetResourceManager(); + + const VulkanRenderState &state = m_pDriver->m_RenderState; + + rdcarray ret; + + if(state.graphics.pipeline != ResourceId()) + ret.append(m_pDriver->m_CreationInfo.m_Pipeline[state.graphics.pipeline].staticDescriptorAccess); + + if(state.compute.pipeline != ResourceId()) + ret.append(m_pDriver->m_CreationInfo.m_Pipeline[state.compute.pipeline].staticDescriptorAccess); + + for(DescriptorAccess &access : ret) + { + uint32_t bindset = (uint32_t)access.byteSize; + access.byteSize = 1; + if(bindset == PushConstantBindSet || bindset == SpecializationConstantBindSet) + { + // TODO + } + else + { + const rdcarray &descSets = + access.stage == ShaderStage::Compute ? state.compute.descSets : state.graphics.descSets; + + if(bindset >= descSets.size()) + { + RDCERR("Unbound descriptor set referenced in static usage"); + } + else + { + access.descriptorStore = rm->GetOriginalID(descSets[bindset].descSet); + } + } + + if(access.descriptorStore == ResourceId()) + access = DescriptorAccess(); + } + + return ret; } void VulkanReplay::FillCBufferVariables(ResourceId pipeline, ResourceId shader, ShaderStage stage, diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 6730e73c0..d56e29644 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -222,6 +222,7 @@ void DoSerialise(SerialiserType &ser, ShaderResource &el) SERIALISE_MEMBER(variableType); SERIALISE_MEMBER(bindPoint); SERIALISE_MEMBER(isTexture); + SERIALISE_MEMBER(hasSampler); SERIALISE_MEMBER(isReadOnly); SIZE_CHECK(112);