diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp index f7de57754..525720801 100644 --- a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp @@ -876,7 +876,7 @@ void D3D11PipelineStateViewer::setShaderState(const D3D11Pipe::Shader &stage, QL const ShaderResource &res = shaderDetails->ReadOnlyResources[b]; const BindpointMap &bind = mapping.ReadOnlyResources[b]; - if(!res.IsSampler && res.IsReadOnly && bind.bind == i) + if(bind.bind == i) { shaderInput = &res; map = &bind; @@ -898,17 +898,17 @@ void D3D11PipelineStateViewer::setShaderState(const D3D11Pipe::Shader &stage, QL { const D3D11Pipe::Sampler &s = stage.Samplers[i]; - const ShaderResource *shaderInput = NULL; + const ShaderSampler *shaderInput = NULL; const BindpointMap *map = NULL; if(shaderDetails) { - for(int b = 0; b < shaderDetails->ReadOnlyResources.count; b++) + for(int b = 0; b < shaderDetails->Samplers.count; b++) { - const ShaderResource &res = shaderDetails->ReadOnlyResources[b]; - const BindpointMap &bind = mapping.ReadOnlyResources[b]; + const ShaderSampler &res = shaderDetails->Samplers[b]; + const BindpointMap &bind = mapping.Samplers[b]; - if(res.IsSampler && bind.bind == i) + if(bind.bind == i) { shaderInput = &res; map = &bind; @@ -1907,7 +1907,7 @@ void D3D11PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, in { for(const ShaderResource &res : searchstage->ShaderDetails->ReadWriteResources) { - if(!res.IsTexture && !res.IsSampler && res.bindPoint == bind) + if(!res.IsTexture && res.bindPoint == bind) { stage = searchstage; break; @@ -1925,7 +1925,7 @@ void D3D11PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, in for(const ShaderResource &res : resArray) { - if(!res.IsTexture && !res.IsSampler && res.bindPoint == bind) + if(!res.IsTexture && res.bindPoint == bind) { shaderRes = &res; break; @@ -2319,7 +2319,7 @@ QVariantList D3D11PipelineStateViewer::exportViewHTML(const D3D11Pipe::View &vie { for(const ShaderResource &bind : refl->ReadOnlyResources) { - if(!bind.IsSampler && bind.bindPoint == i) + if(bind.bindPoint == i) { shaderInput = &bind; break; diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp index 01f81e1ff..142ee56d0 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp @@ -646,7 +646,7 @@ void D3D12PipelineStateViewer::addResourceRow(const D3D12ViewTag &view, if(b.bind <= view.reg) regMatch = (b.arraySize == ~0U) || (b.bind + (int)b.arraySize > view.reg); - if(b.bindset == view.space && regMatch && !res[i].IsSampler) + if(b.bindset == view.space && regMatch) { bind = &b; shaderInput = &res[i]; @@ -976,14 +976,14 @@ void D3D12PipelineStateViewer::setShaderState(const D3D12Pipe::Shader &stage, QL continue; const BindpointMap *bind = NULL; - const ShaderResource *shaderInput = NULL; + const ShaderSampler *shaderInput = NULL; if(stage.ShaderDetails) { - for(int i = 0; i < stage.BindpointMapping.ReadOnlyResources.count; i++) + for(int i = 0; i < stage.BindpointMapping.Samplers.count; i++) { - const BindpointMap &b = stage.BindpointMapping.ReadOnlyResources[i]; - const ShaderResource &res = stage.ShaderDetails->ReadOnlyResources[i]; + const BindpointMap &b = stage.BindpointMapping.Samplers[i]; + const ShaderSampler &res = stage.ShaderDetails->Samplers[i]; bool regMatch = b.bind == reg; @@ -992,7 +992,7 @@ void D3D12PipelineStateViewer::setShaderState(const D3D12Pipe::Shader &stage, QL if(b.bind <= reg) regMatch = (b.arraySize == ~0U) || (b.bind + (int)b.arraySize > reg); - if(b.bindset == space && regMatch && res.IsSampler) + if(b.bindset == space && regMatch) { bind = &b; shaderInput = &res; @@ -1774,8 +1774,7 @@ void D3D12PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, in for(int i = 0; i < bindArray.count; i++) { - if(bindArray[i].bindset == view.space && bindArray[i].bind == view.reg && - !resArray[i].IsSampler) + if(bindArray[i].bindset == view.space && bindArray[i].bind == view.reg) { shaderRes = &resArray[i]; break; @@ -2423,7 +2422,7 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe if(b.bind <= reg) regMatch = (b.arraySize == ~0U) || (b.bind + (int)b.arraySize > reg); - if(b.bindset == space && regMatch && !res.IsReadOnly && !res.IsSampler) + if(b.bindset == space && regMatch) { shaderInput = &res; break; @@ -2473,10 +2472,10 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe if(sh.ShaderDetails) { - for(int i = 0; i < sh.BindpointMapping.ReadOnlyResources.count; i++) + for(int i = 0; i < sh.BindpointMapping.ReadWriteResources.count; i++) { - const BindpointMap &b = sh.BindpointMapping.ReadOnlyResources[i]; - const ShaderResource &res = sh.ShaderDetails->ReadOnlyResources[i]; + const BindpointMap &b = sh.BindpointMapping.ReadWriteResources[i]; + const ShaderResource &res = sh.ShaderDetails->ReadWriteResources[i]; bool regMatch = b.bind == reg; @@ -2485,7 +2484,7 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe if(b.bind <= reg) regMatch = (b.arraySize == ~0U) || (b.bind + (int)b.arraySize > reg); - if(b.bindset == space && regMatch && !res.IsReadOnly && !res.IsSampler) + if(b.bindset == space && regMatch) { shaderInput = &res; break; @@ -2531,14 +2530,14 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe if(s.RootElement == ~0U) continue; - const ShaderResource *shaderInput = NULL; + const ShaderSampler *shaderInput = NULL; if(sh.ShaderDetails) { - for(int i = 0; i < sh.BindpointMapping.ReadOnlyResources.count; i++) + for(int i = 0; i < sh.BindpointMapping.Samplers.count; i++) { - const BindpointMap &b = sh.BindpointMapping.ReadOnlyResources[i]; - const ShaderResource &res = sh.ShaderDetails->ReadOnlyResources[i]; + const BindpointMap &b = sh.BindpointMapping.Samplers[i]; + const ShaderSampler &res = sh.ShaderDetails->Samplers[i]; bool regMatch = b.bind == reg; @@ -2547,7 +2546,7 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe if(b.bind <= reg) regMatch = (b.arraySize == ~0U) || (b.bind + (int)b.arraySize > reg); - if(b.bindset == space && regMatch && res.IsSampler) + if(b.bindset == space && regMatch) { shaderInput = &res; break; diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp index dd94620ea..fb4bb66c3 100644 --- a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp @@ -618,49 +618,47 @@ QString PipelineStateViewer::GenerateHLSLStub(const ShaderReflection *shaderDeta lit("Texture2DMSArray"), lit("Texture3D"), lit("TextureCube"), lit("TextureCubeArray"), }; + for(const ShaderSampler &samp : shaderDetails->Samplers) + { + hlsl += lit("//SamplerComparisonState %1 : register(s%2); // can't disambiguate\n" + "SamplerState %1 : register(s%2); // can't disambiguate\n") + .arg(samp.name) + .arg(samp.bindPoint); + } + for(int i = 0; i < 2; i++) { const rdctype::array &resources = (i == 0 ? shaderDetails->ReadOnlyResources : shaderDetails->ReadWriteResources); for(const ShaderResource &res : resources) { - if(res.IsSampler) + char regChar = 't'; + + if(i == 1) { - hlsl += lit("//SamplerComparisonState %1 : register(s%2); // can't disambiguate\n" - "SamplerState %1 : register(s%2); // can't disambiguate\n") + hlsl += lit("RW"); + regChar = 'u'; + } + + if(res.IsTexture) + { + hlsl += lit("%1<%2> %3 : register(%4%5);\n") + .arg(textureDim[(size_t)res.resType]) + .arg(res.variableType.descriptor.name) .arg(res.name) + .arg(QLatin1Char(regChar)) .arg(res.bindPoint); } else { - char regChar = 't'; + if(res.variableType.descriptor.rows > 1) + hlsl += lit("Structured"); - if(i == 1) - { - hlsl += lit("RW"); - regChar = 'u'; - } - - if(res.IsTexture) - { - hlsl += lit("%1<%2> %3 : register(%4%5);\n") - .arg(textureDim[(size_t)res.resType]) - .arg(res.variableType.descriptor.name) - .arg(res.name) - .arg(QLatin1Char(regChar)) - .arg(res.bindPoint); - } - else - { - if(res.variableType.descriptor.rows > 1) - hlsl += lit("Structured"); - - hlsl += lit("Buffer<%1> %2 : register(%3%4);\n") - .arg(res.variableType.descriptor.name) - .arg(res.name) - .arg(QLatin1Char(regChar)) - .arg(res.bindPoint); - } + hlsl += lit("Buffer<%1> %2 : register(%3%4);\n") + .arg(res.variableType.descriptor.name) + .arg(res.name) + .arg(QLatin1Char(regChar)) + .arg(res.bindPoint); } } } diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp index 2429dfcc1..8217e1059 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp @@ -712,14 +712,10 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, } else { - if(shaderRes->IsSampler) - bindType = BindType::Sampler; - else if(shaderRes->IsSampler && shaderRes->IsTexture) - bindType = BindType::ImageSampler; - else if(shaderRes->resType == TextureDim::Buffer) - bindType = BindType::ReadOnlyTBuffer; + if(shaderRes->resType == TextureDim::Buffer) + bindType = isrw ? BindType::ReadWriteBuffer : BindType::ReadOnlyBuffer; else - bindType = BindType::ReadOnlyImage; + bindType = isrw ? BindType::ReadWriteImage : BindType::ReadOnlyImage; } bool usedSlot = bindMap != NULL && bindMap->used; diff --git a/qrenderdoc/Windows/ShaderViewer.cpp b/qrenderdoc/Windows/ShaderViewer.cpp index be0d93d39..0dc6dba7a 100644 --- a/qrenderdoc/Windows/ShaderViewer.cpp +++ b/qrenderdoc/Windows/ShaderViewer.cpp @@ -1024,9 +1024,6 @@ RDTreeWidgetItem *ShaderViewer::makeResourceRegister(const BindpointMap &bind, u const TextureDescription *tex = m_Ctx.GetTexture(bound.Id); const BufferDescription *buf = m_Ctx.GetBuffer(bound.Id); - if(res.IsSampler) - return NULL; - QChar regChar(QLatin1Char('u')); if(res.IsReadOnly) diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index 12ffa205c..c1827bb19 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -2006,33 +2006,18 @@ void TextureViewer::InitStageResourcePreviews(ShaderStage stage, CompType typeHint = resArray != NULL ? resArray->at(arrayIdx).typeHint : CompType::Typeless; bool used = key.used; - bool samplerBind = false; - bool otherBind = false; QString bindName; - for(int b = 0; b < resourceDetails.count; b++) + for(const ShaderResource &bind : resourceDetails) { - const ShaderResource &bind = resourceDetails[b]; - if(bind.bindPoint == idx && bind.IsReadOnly) - { - bindName = bind.name; - otherBind = true; - break; - } - if(bind.bindPoint == idx) { - if(bind.IsSampler && !bind.IsReadOnly) - samplerBind = true; - else - otherBind = true; + bindName = bind.name; + break; } } - if(samplerBind && !otherBind) - continue; - if(copy) { used = true; diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index 582542e28..67373624f 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -399,10 +399,30 @@ specialisation constants. DECLARE_REFLECTION_STRUCT(ConstantBlock); +DOCUMENT(R"(Contains the information for a separate sampler in a shader. If the API doesn't have +the concept of separate samplers, this struct will be unused and only :class:`ShaderResource` is +relevant. + +.. note:: that constant blocks will not have a shader resource entry, see :class:`ConstantBlock`. +)"); +struct ShaderSampler +{ + DOCUMENT("The name of this sampler."); + rdctype::str name; + + DOCUMENT(R"(The bindpoint for this block. This is an index in either the +:data:`ShaderBindpointMapping.Samplers` list. +)"); + int32_t bindPoint; +}; + +DECLARE_REFLECTION_STRUCT(ShaderSampler); + DOCUMENT(R"(Contains the information for a shader resource that is made accessible to shaders directly by means of the API resource binding system. -.. note:: that constant blocks will not have a shader resource entry, see :class:`ConstantBlock`. +.. note:: that constant blocks and samplers will not have a shader resource entry, see + :class:`ConstantBlock` and :class:`ShaderSampler`. )"); struct ShaderResource { @@ -421,14 +441,6 @@ struct ShaderResource )"); int32_t bindPoint; - DOCUMENT(R"(``True`` if this resource is a sampler. - -If the API has no concept of separate samplers, this will always be ``False``. - -.. note:: this is not exclusive with the other flags in the case of e.g. combined sampler/texture - objects. -)"); - bool IsSampler; DOCUMENT(R"(``True`` if this resource is a texture, otherwise it is a buffer or sampler (see :data:`IsSampler`). )"); @@ -503,6 +515,9 @@ struct ShaderReflection DOCUMENT("A list of :class:`ConstantBlock` with the shader's constant bindings."); rdctype::array ConstantBlocks; + DOCUMENT("A list of :class:`ShaderSampler` with the shader's samplers."); + rdctype::array Samplers; + DOCUMENT("A list of :class:`ShaderResource` with the shader's read-only resources."); rdctype::array ReadOnlyResources; DOCUMENT("A list of :class:`ShaderResource` with the shader's read-write resources."); @@ -571,19 +586,8 @@ API specific details: :data:`BindpointMap.arraySize` is likewise unused as D3D11 doesn't have arrayed resource bindings. - The :data:`BindpointMap.bind` value corresponds directly to the index in the appropriate resource - list. - - One important thing to note is that samplers are included with read only resources. This means - consumers wanting to map to API bindpoints should know and expect that the - :data:`ReadOnlyResources` list contains potentially duplicate :class:`BindpointMap`, with one - being a SRV and one a sampler. - - Note that D3D11 currently uses an identity bindpoint mapping, such that the index in the bindpoint - array is equal to the register, even if it's sparse. E.g. textures ``0`` and ``4`` will be in - bindpoint maps ``0`` and ``4`` with three empty unused maps in ``1``, ``2``, and ``3``. This is - not contractual and should not be relied upon, in future the bindpoint map may be only two - elements that list ``0`` and ``4``, with the shader bindpoints then being ``0`` and ``1``. + :data:`BindpointMap.bind` refers to the register/slot binding within the appropriate type (SRVs for + read-only resources, UAV for read-write resources, samplers/constant buffers in each type). * OpenGL - Similarly to D3D11, :data:`BindpointMap.bindset` and :data:`BindpointMap.arraySize` are unused as OpenGL does not have true binding sets or array resource binds. @@ -594,9 +598,8 @@ API specific details: the :data:`ReadWriteResources` list. The index is the uniform value of the binding. Since no objects are namespaced by shader stage, the same value in two shaders refers to the same binding. -* Direct3D12 - As with 11 above, samplers are included in the read only resources array. Likewise - since D3D12 doesn't have true resource arrays (they are linearised into sequential registers) - :data:`BindpointMap.arraySize` is not used. +* Direct3D12 - Since D3D12 doesn't have true resource arrays (they are linearised into sequential + registers) :data:`BindpointMap.arraySize` is not used. :data:`BindpointMap.bindset` corresponds to register spaces, with :data:`BindpointMap.bind` then mapping to the register within that space. The root signature then maps these registers to @@ -619,6 +622,11 @@ struct ShaderBindpointMapping )"); rdctype::array ConstantBlocks; + DOCUMENT(R"(Provides a list of :class:`BindpointMap` entries for remapping the +:data:`ShaderReflection.Samplers` list. +)"); + rdctype::array Samplers; + DOCUMENT(R"(Provides a list of :class:`BindpointMap` entries for remapping the :data:`ShaderReflection.ReadOnlyResources` list. )"); diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index 552893598..a21f8f21a 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -128,10 +128,11 @@ void Serialiser::Serialise(const char *name, ShaderBindpointMapping &el) { Serialise("", el.InputAttributes); Serialise("", el.ConstantBlocks); + Serialise("", el.Samplers); Serialise("", el.ReadOnlyResources); Serialise("", el.ReadWriteResources); - SIZE_CHECK(64); + SIZE_CHECK(80); } template <> @@ -193,10 +194,18 @@ void Serialiser::Serialise(const char *name, ConstantBlock &el) SIZE_CHECK(48); } +template <> +void Serialiser::Serialise(const char *name, ShaderSampler &el) +{ + Serialise("", el.name); + Serialise("", el.bindPoint); + + SIZE_CHECK(24); +} + template <> void Serialiser::Serialise(const char *name, ShaderResource &el) { - Serialise("", el.IsSampler); Serialise("", el.IsTexture); Serialise("", el.IsReadOnly); Serialise("", el.resType); @@ -241,12 +250,14 @@ void Serialiser::Serialise(const char *name, ShaderReflection &el) Serialise("", el.ConstantBlocks); + Serialise("", el.Samplers); + Serialise("", el.ReadOnlyResources); Serialise("", el.ReadWriteResources); Serialise("", el.Interfaces); - SIZE_CHECK(184); + SIZE_CHECK(200); } template <> @@ -401,7 +412,7 @@ void Serialiser::Serialise(const char *name, D3D11Pipe::Shader &el) Serialise("", el.ConstantBuffers); Serialise("", el.ClassInstances); - SIZE_CHECK(192); + SIZE_CHECK(208); } template <> @@ -496,7 +507,7 @@ void Serialiser::Serialise(const char *name, D3D11Pipe::State &el) Serialise("", el.m_RS); Serialise("", el.m_OM); - SIZE_CHECK(1560); + SIZE_CHECK(1656); } #pragma endregion D3D11 pipeline state @@ -616,7 +627,7 @@ void Serialiser::Serialise(const char *name, D3D12Pipe::Shader &el) Serialise("", el.stage); Serialise("", el.Spaces); - SIZE_CHECK(104); + SIZE_CHECK(120); } template <> @@ -735,7 +746,7 @@ void Serialiser::Serialise(const char *name, D3D12Pipe::State &el) Serialise("", el.Resources); - SIZE_CHECK(1080); + SIZE_CHECK(1176); } #pragma endregion D3D12 pipeline state @@ -789,7 +800,7 @@ void Serialiser::Serialise(const char *name, GLPipe::Shader &el) if(m_Mode == READING) el.ShaderDetails = NULL; - SIZE_CHECK(176); + SIZE_CHECK(192); } template <> @@ -967,7 +978,7 @@ void Serialiser::Serialise(const char *name, GLPipe::State &el) Serialise("", el.m_Hints); - SIZE_CHECK(1832); + SIZE_CHECK(1928); } #pragma endregion OpenGL pipeline state @@ -1090,7 +1101,7 @@ void Serialiser::Serialise(const char *name, VKPipe::Shader &el) Serialise("", el.specialization); - SIZE_CHECK(144); + SIZE_CHECK(160); } template <> @@ -1251,7 +1262,7 @@ void Serialiser::Serialise(const char *name, VKPipe::State &el) Serialise("", el.images); - SIZE_CHECK(1328); + SIZE_CHECK(1424); } #pragma endregion Vulkan pipeline state diff --git a/renderdoc/driver/d3d11/d3d11_analyse.cpp b/renderdoc/driver/d3d11/d3d11_analyse.cpp index 67c660335..8d9d4d6bc 100644 --- a/renderdoc/driver/d3d11/d3d11_analyse.cpp +++ b/renderdoc/driver/d3d11/d3d11_analyse.cpp @@ -853,7 +853,7 @@ void D3D11DebugManager::CreateShaderGlobalState(ShaderDebug::GlobalState &global global.srvs[i].format.stride = bufdesc.StructureByteStride; // if we didn't get a type from the SRV description, try to pull it from the declaration - for(const DXBC::ShaderInputBind &bind : dxbc->m_Resources) + for(const DXBC::ShaderInputBind &bind : dxbc->m_SRVs) { if(bind.reg == (uint32_t)i && bind.dimension == DXBC::ShaderInputBind::DIM_BUFFER && bind.retType < DXBC::ShaderInputBind::RETTYPE_MIXED && diff --git a/renderdoc/driver/d3d11/d3d11_renderstate.cpp b/renderdoc/driver/d3d11/d3d11_renderstate.cpp index 9dd430bb0..f223948f8 100644 --- a/renderdoc/driver/d3d11/d3d11_renderstate.cpp +++ b/renderdoc/driver/d3d11/d3d11_renderstate.cpp @@ -1519,17 +1519,9 @@ bool D3D11RenderState::shader::Used_SRV(uint32_t slot) const if(dxbc == NULL) return true; - for(size_t i = 0; i < dxbc->m_Resources.size(); i++) - { - if(dxbc->m_Resources[i].reg == slot && - (dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_TEXTURE || - dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_STRUCTURED || - dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_TBUFFER || - dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_BYTEADDRESS)) - { + for(const DXBC::ShaderInputBind &bind : dxbc->m_SRVs) + if(bind.reg == slot) return true; - } - } return false; } @@ -1547,19 +1539,9 @@ bool D3D11RenderState::shader::Used_UAV(uint32_t slot) const if(dxbc == NULL) return true; - for(size_t i = 0; i < dxbc->m_Resources.size(); i++) - { - if(dxbc->m_Resources[i].reg == slot && - (dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_UAV_APPEND_STRUCTURED || - dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_UAV_CONSUME_STRUCTURED || - dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_UAV_RWBYTEADDRESS || - dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED || - dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED_WITH_COUNTER || - dxbc->m_Resources[i].type == DXBC::ShaderInputBind::TYPE_UAV_RWTYPED)) - { + for(const DXBC::ShaderInputBind &bind : dxbc->m_UAVs) + if(bind.reg == slot) return true; - } - } return false; } diff --git a/renderdoc/driver/gl/gl_shader_refl.cpp b/renderdoc/driver/gl/gl_shader_refl.cpp index 2f6ad8076..e5f07b3c7 100644 --- a/renderdoc/driver/gl/gl_shader_refl.cpp +++ b/renderdoc/driver/gl/gl_shader_refl.cpp @@ -922,7 +922,6 @@ void MakeShaderReflection(const GLHookSet &gl, GLenum shadType, GLuint sepProg, gl.glGetProgramResourceiv(sepProg, eGL_UNIFORM, u, numProps, resProps, numProps, NULL, values); ShaderResource res; - res.IsSampler = false; // no separate sampler objects in GL res.IsReadOnly = true; res.IsTexture = true; res.variableType.descriptor.rows = 1; @@ -1465,7 +1464,6 @@ void MakeShaderReflection(const GLHookSet &gl, GLenum shadType, GLuint sepProg, gl.glGetProgramResourceName(sepProg, eGL_SHADER_STORAGE_BLOCK, u, len + 1, NULL, nm); ShaderResource res; - res.IsSampler = false; res.IsReadOnly = false; res.IsTexture = false; res.resType = TextureDim::Buffer; diff --git a/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp b/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp index efd17d1bc..ca7ea79ac 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp @@ -982,14 +982,22 @@ string ASMOperand::toString(DXBCFile *dxbc, ToString flags) const { uint32_t idx = (uint32_t)indices[0].index; - for(const ShaderInputBind &b : dxbc->m_Resources) - { - if(b.reg != idx || b.space != 0) - continue; + vector *list = NULL; - if((type == TYPE_RESOURCE && b.IsROResource()) || (type == TYPE_SAMPLER && b.IsSampler()) || - (type == TYPE_UNORDERED_ACCESS_VIEW && b.IsUAV())) + if(type == TYPE_RESOURCE) + list = &dxbc->m_SRVs; + else if(type == TYPE_UNORDERED_ACCESS_VIEW) + list = &dxbc->m_UAVs; + else if(type == TYPE_SAMPLER) + list = &dxbc->m_Samplers; + + if(list) + { + for(const ShaderInputBind &b : *list) { + if(b.reg != idx || b.space != 0) + continue; + if(decl) regstr = str; str = b.name; diff --git a/renderdoc/driver/shaders/dxbc/dxbc_inspect.cpp b/renderdoc/driver/shaders/dxbc/dxbc_inspect.cpp index ccb4b8daf..b388412c9 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_inspect.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_inspect.cpp @@ -594,7 +594,9 @@ DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) else if(h->targetShaderStage == 0x4353) // 'CS' m_Type = D3D11_ShaderType_Compute; - m_Resources.reserve(h->resources.count); + m_SRVs.reserve(h->resources.count); + m_UAVs.reserve(h->resources.count); + m_Samplers.reserve(h->resources.count); struct CBufferBind { @@ -639,7 +641,7 @@ DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) // for cbuffers the names can be duplicated, so handle this by assuming // the order will match between binding declaration and cbuffer declaration // and append _s onto each subsequent buffer name - if(desc.type == ShaderInputBind::TYPE_CBUFFER) + if(desc.IsCBuffer()) { string cname = desc.name; @@ -652,8 +654,22 @@ DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) cb.bindCount = desc.bindCount; cbufferbinds[cname] = cb; } - - m_Resources.push_back(desc); + else if(desc.IsSampler()) + { + m_Samplers.push_back(desc); + } + else if(desc.IsSRV()) + { + m_SRVs.push_back(desc); + } + else if(desc.IsUAV()) + { + m_UAVs.push_back(desc); + } + else + { + RDCERR("Unexpected type of resource: %u", desc.type); + } } // Expand out any array resources. We deliberately place these at the end of the resources @@ -666,31 +682,35 @@ DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) // Note we preserve the arrays in SM5.1 if(h->targetVersion < 0x501) { - for(size_t i = 0; i < m_Resources.size();) + for(vector *arr : {&m_SRVs, &m_UAVs, &m_Samplers}) { - if(m_Resources[i].bindCount > 1) + vector &resArray = *arr; + for(size_t i = 0; i < resArray.size();) { - ShaderInputBind desc = m_Resources[i]; - m_Resources.erase(m_Resources.begin() + i); - - string rname = desc.name; - uint32_t arraySize = desc.bindCount; - - desc.bindCount = 1; - - for(uint32_t a = 0; a < arraySize; a++) + if(resArray[i].bindCount > 1) { - desc.name = StringFormat::Fmt("%s[%u]", rname.c_str(), a); - m_Resources.push_back(desc); - desc.reg++; + ShaderInputBind desc = resArray[i]; + resArray.erase(resArray.begin() + i); + + string rname = desc.name; + uint32_t arraySize = desc.bindCount; + + desc.bindCount = 1; + + for(uint32_t a = 0; a < arraySize; a++) + { + desc.name = StringFormat::Fmt("%s[%u]", rname.c_str(), a); + resArray.push_back(desc); + desc.reg++; + } + + // continue from the i'th element again since + // we just removed it. + continue; } - // continue from the i'th element again since - // we just removed it. - continue; + i++; } - - i++; } } @@ -1071,7 +1091,7 @@ void DXBCFile::GuessResources() desc.bindCount = 0; } - m_Resources.push_back(desc); + m_Samplers.push_back(desc); break; } @@ -1136,7 +1156,7 @@ void DXBCFile::GuessResources() desc.bindCount = 0; } - m_Resources.push_back(desc); + m_SRVs.push_back(desc); break; } @@ -1173,7 +1193,10 @@ void DXBCFile::GuessResources() desc.bindCount = 0; } - m_Resources.push_back(desc); + if(dcl.operand.type == TYPE_RESOURCE) + m_SRVs.push_back(desc); + else + m_UAVs.push_back(desc); break; } @@ -1206,7 +1229,7 @@ void DXBCFile::GuessResources() desc.bindCount = 0; } - m_Resources.push_back(desc); + m_SRVs.push_back(desc); break; } @@ -1243,7 +1266,7 @@ void DXBCFile::GuessResources() desc.bindCount = 0; } - m_Resources.push_back(desc); + m_UAVs.push_back(desc); break; } @@ -1302,7 +1325,7 @@ void DXBCFile::GuessResources() desc.bindCount = 0; } - m_Resources.push_back(desc); + m_UAVs.push_back(desc); break; } @@ -1338,8 +1361,6 @@ void DXBCFile::GuessResources() CBuffer cb; - m_Resources.push_back(desc); - cb.name = desc.name; cb.space = dcl.space; diff --git a/renderdoc/driver/shaders/dxbc/dxbc_inspect.h b/renderdoc/driver/shaders/dxbc/dxbc_inspect.h index e6557b6af..f23e9cb50 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_inspect.h +++ b/renderdoc/driver/shaders/dxbc/dxbc_inspect.h @@ -139,7 +139,7 @@ struct ShaderInputBind constexpr bool IsCBuffer() const { return type == TYPE_CBUFFER; } constexpr bool IsSampler() const { return type == TYPE_SAMPLER; } - constexpr bool IsROResource() const + constexpr bool IsSRV() const { return type == TYPE_TBUFFER || type == TYPE_TEXTURE || type == TYPE_STRUCTURED || type == TYPE_BYTEADDRESS; @@ -369,7 +369,10 @@ public: vector m_Immediate; bool m_GuessedResources; - vector m_Resources; + vector m_SRVs; + vector m_UAVs; + + vector m_Samplers; vector m_CBuffers; diff --git a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp index dd91373f3..b19d7d0e4 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp @@ -108,6 +108,102 @@ static ShaderConstant MakeConstantBufferVariable(const DXBC::CBufferVariable &va return ret; } +static void MakeResourceList(bool srv, DXBC::DXBCFile *dxbc, const vector &in, + rdctype::array &mapping, + rdctype::array &refl) +{ + for(size_t i = 0; i < in.size(); i++) + { + const DXBC::ShaderInputBind &r = in[i]; + + ShaderResource res; + res.name = r.name; + + res.IsTexture = (r.type == DXBC::ShaderInputBind::TYPE_TEXTURE && + r.dimension != DXBC::ShaderInputBind::DIM_UNKNOWN && + r.dimension != DXBC::ShaderInputBind::DIM_BUFFER && + r.dimension != DXBC::ShaderInputBind::DIM_BUFFEREX); + res.IsReadOnly = srv; + + switch(r.dimension) + { + default: + case DXBC::ShaderInputBind::DIM_UNKNOWN: res.resType = TextureDim::Unknown; break; + case DXBC::ShaderInputBind::DIM_BUFFER: + case DXBC::ShaderInputBind::DIM_BUFFEREX: res.resType = TextureDim::Buffer; break; + case DXBC::ShaderInputBind::DIM_TEXTURE1D: res.resType = TextureDim::Texture1D; break; + case DXBC::ShaderInputBind::DIM_TEXTURE1DARRAY: + res.resType = TextureDim::Texture1DArray; + break; + case DXBC::ShaderInputBind::DIM_TEXTURE2D: res.resType = TextureDim::Texture2D; break; + case DXBC::ShaderInputBind::DIM_TEXTURE2DARRAY: + res.resType = TextureDim::Texture2DArray; + break; + case DXBC::ShaderInputBind::DIM_TEXTURE2DMS: res.resType = TextureDim::Texture2DMS; break; + case DXBC::ShaderInputBind::DIM_TEXTURE2DMSARRAY: + res.resType = TextureDim::Texture2DMSArray; + break; + case DXBC::ShaderInputBind::DIM_TEXTURE3D: res.resType = TextureDim::Texture3D; break; + case DXBC::ShaderInputBind::DIM_TEXTURECUBE: res.resType = TextureDim::TextureCube; break; + case DXBC::ShaderInputBind::DIM_TEXTURECUBEARRAY: + res.resType = TextureDim::TextureCubeArray; + break; + } + + if(r.retType != DXBC::ShaderInputBind::RETTYPE_UNKNOWN && + r.retType != DXBC::ShaderInputBind::RETTYPE_MIXED && + r.retType != DXBC::ShaderInputBind::RETTYPE_CONTINUED) + { + res.variableType.descriptor.rows = 1; + res.variableType.descriptor.cols = (uint8_t)r.numSamples; + res.variableType.descriptor.elements = 1; + + string name; + + switch(r.retType) + { + case DXBC::ShaderInputBind::RETTYPE_UNORM: name = "unorm float"; break; + case DXBC::ShaderInputBind::RETTYPE_SNORM: name = "snorm float"; break; + case DXBC::ShaderInputBind::RETTYPE_SINT: name = "int"; break; + case DXBC::ShaderInputBind::RETTYPE_UINT: name = "uint"; break; + case DXBC::ShaderInputBind::RETTYPE_FLOAT: name = "float"; break; + case DXBC::ShaderInputBind::RETTYPE_DOUBLE: name = "double"; break; + default: name = "unknown"; break; + } + + name += StringFormat::Fmt("%u", r.numSamples); + + res.variableType.descriptor.name = name; + } + else + { + if(dxbc->m_ResourceBinds.find(r.name) != dxbc->m_ResourceBinds.end()) + { + uint32_t vecOffset = 0; + res.variableType = MakeShaderVariableType(dxbc->m_ResourceBinds[r.name], vecOffset); + } + else + { + res.variableType.descriptor.rows = 0; + res.variableType.descriptor.cols = 0; + res.variableType.descriptor.elements = 0; + res.variableType.descriptor.name = ""; + } + } + + res.bindPoint = (int32_t)i; + + BindpointMap map; + map.arraySize = r.bindCount == 0 ? ~0U : r.bindCount; + map.bindset = r.space; + map.bind = r.reg; + map.used = true; + + mapping[i] = map; + refl[i] = res; + } +} + void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl, ShaderBindpointMapping *mapping) { @@ -204,7 +300,7 @@ void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl, cb.name = dxbc->m_CBuffers[i].name; cb.bufferBacked = true; cb.byteSize = dxbc->m_CBuffers[i].descriptor.byteSize; - cb.bindPoint = (uint32_t)i; + cb.bindPoint = (int32_t)i; BindpointMap map; map.arraySize = 1; @@ -222,143 +318,32 @@ void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl, } } - int numRWResources = 0; - int numROResources = 0; - - for(size_t i = 0; i < dxbc->m_Resources.size(); i++) + create_array_uninit(mapping->Samplers, dxbc->m_Samplers.size()); + create_array_uninit(refl->Samplers, dxbc->m_Samplers.size()); + for(size_t i = 0; i < dxbc->m_Samplers.size(); i++) { - const auto &r = dxbc->m_Resources[i]; + ShaderSampler &s = refl->Samplers[i]; - if(r.type != DXBC::ShaderInputBind::TYPE_CBUFFER) - { - bool IsReadWrite = (r.type == DXBC::ShaderInputBind::TYPE_UAV_RWTYPED || - r.type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED || - r.type == DXBC::ShaderInputBind::TYPE_UAV_RWBYTEADDRESS || - r.type == DXBC::ShaderInputBind::TYPE_UAV_APPEND_STRUCTURED || - r.type == DXBC::ShaderInputBind::TYPE_UAV_CONSUME_STRUCTURED || - r.type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED_WITH_COUNTER); - - if(IsReadWrite) - numRWResources++; - else - numROResources++; - } - } - - create_array_uninit(mapping->ReadWriteResources, numRWResources); - create_array_uninit(refl->ReadWriteResources, numRWResources); - - create_array_uninit(mapping->ReadOnlyResources, numROResources); - create_array_uninit(refl->ReadOnlyResources, numROResources); - - int32_t rwidx = 0, roidx = 0; - for(size_t i = 0; i < dxbc->m_Resources.size(); i++) - { - const auto &r = dxbc->m_Resources[i]; - - if(r.type == DXBC::ShaderInputBind::TYPE_CBUFFER) - continue; - - ShaderResource res; - res.name = r.name; - - res.IsSampler = (r.type == DXBC::ShaderInputBind::TYPE_SAMPLER); - res.IsTexture = (r.type == DXBC::ShaderInputBind::TYPE_TEXTURE && - r.dimension != DXBC::ShaderInputBind::DIM_UNKNOWN && - r.dimension != DXBC::ShaderInputBind::DIM_BUFFER && - r.dimension != DXBC::ShaderInputBind::DIM_BUFFEREX); - res.IsReadOnly = (r.type == DXBC::ShaderInputBind::TYPE_TBUFFER || - r.type == DXBC::ShaderInputBind::TYPE_SAMPLER || - r.type == DXBC::ShaderInputBind::TYPE_TEXTURE || - r.type == DXBC::ShaderInputBind::TYPE_STRUCTURED || - r.type == DXBC::ShaderInputBind::TYPE_BYTEADDRESS); - - switch(r.dimension) - { - default: - case DXBC::ShaderInputBind::DIM_UNKNOWN: res.resType = TextureDim::Unknown; break; - case DXBC::ShaderInputBind::DIM_BUFFER: - case DXBC::ShaderInputBind::DIM_BUFFEREX: res.resType = TextureDim::Buffer; break; - case DXBC::ShaderInputBind::DIM_TEXTURE1D: res.resType = TextureDim::Texture1D; break; - case DXBC::ShaderInputBind::DIM_TEXTURE1DARRAY: - res.resType = TextureDim::Texture1DArray; - break; - case DXBC::ShaderInputBind::DIM_TEXTURE2D: res.resType = TextureDim::Texture2D; break; - case DXBC::ShaderInputBind::DIM_TEXTURE2DARRAY: - res.resType = TextureDim::Texture2DArray; - break; - case DXBC::ShaderInputBind::DIM_TEXTURE2DMS: res.resType = TextureDim::Texture2DMS; break; - case DXBC::ShaderInputBind::DIM_TEXTURE2DMSARRAY: - res.resType = TextureDim::Texture2DMSArray; - break; - case DXBC::ShaderInputBind::DIM_TEXTURE3D: res.resType = TextureDim::Texture3D; break; - case DXBC::ShaderInputBind::DIM_TEXTURECUBE: res.resType = TextureDim::TextureCube; break; - case DXBC::ShaderInputBind::DIM_TEXTURECUBEARRAY: - res.resType = TextureDim::TextureCubeArray; - break; - } - - if(r.retType != DXBC::ShaderInputBind::RETTYPE_UNKNOWN && - r.retType != DXBC::ShaderInputBind::RETTYPE_MIXED && - r.retType != DXBC::ShaderInputBind::RETTYPE_CONTINUED) - { - res.variableType.descriptor.rows = 1; - res.variableType.descriptor.cols = (uint8_t)r.numSamples; - res.variableType.descriptor.elements = 1; - - string name; - - switch(r.retType) - { - case DXBC::ShaderInputBind::RETTYPE_UNORM: name = "unorm float"; break; - case DXBC::ShaderInputBind::RETTYPE_SNORM: name = "snorm float"; break; - case DXBC::ShaderInputBind::RETTYPE_SINT: name = "int"; break; - case DXBC::ShaderInputBind::RETTYPE_UINT: name = "uint"; break; - case DXBC::ShaderInputBind::RETTYPE_FLOAT: name = "float"; break; - case DXBC::ShaderInputBind::RETTYPE_DOUBLE: name = "double"; break; - default: name = "unknown"; break; - } - - name += StringFormat::Fmt("%u", r.numSamples); - - res.variableType.descriptor.name = name; - } - else - { - if(dxbc->m_ResourceBinds.find(r.name) != dxbc->m_ResourceBinds.end()) - { - uint32_t vecOffset = 0; - res.variableType = MakeShaderVariableType(dxbc->m_ResourceBinds[r.name], vecOffset); - } - else - { - res.variableType.descriptor.rows = 0; - res.variableType.descriptor.cols = 0; - res.variableType.descriptor.elements = 0; - res.variableType.descriptor.name = ""; - } - } - - res.bindPoint = res.IsReadOnly ? roidx : rwidx; + s.name = dxbc->m_Samplers[i].name; + s.bindPoint = (int32_t)i; BindpointMap map; - map.arraySize = r.bindCount == 0 ? ~0U : r.bindCount; - map.bindset = r.space; - map.bind = r.reg; + map.arraySize = 1; + map.bindset = dxbc->m_Samplers[i].space; + map.bind = dxbc->m_Samplers[i].reg; map.used = true; - if(res.IsReadOnly) - { - mapping->ReadOnlyResources[roidx] = map; - refl->ReadOnlyResources[roidx++] = res; - } - else - { - mapping->ReadWriteResources[rwidx] = map; - refl->ReadWriteResources[rwidx++] = res; - } + mapping->Samplers[i] = map; } + create_array_uninit(mapping->ReadOnlyResources, dxbc->m_SRVs.size()); + create_array_uninit(refl->ReadOnlyResources, dxbc->m_SRVs.size()); + MakeResourceList(true, dxbc, dxbc->m_SRVs, mapping->ReadOnlyResources, refl->ReadOnlyResources); + + create_array_uninit(mapping->ReadWriteResources, dxbc->m_UAVs.size()); + create_array_uninit(refl->ReadWriteResources, dxbc->m_UAVs.size()); + MakeResourceList(true, dxbc, dxbc->m_UAVs, mapping->ReadWriteResources, refl->ReadWriteResources); + uint32_t numInterfaces = 0; for(size_t i = 0; i < dxbc->m_Interfaces.variables.size(); i++) numInterfaces = RDCMAX(dxbc->m_Interfaces.variables[i].descriptor.offset + 1, numInterfaces); diff --git a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp index 2a30b22e5..79602108c 100644 --- a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp @@ -3901,7 +3901,7 @@ void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint, vector inputs; vector outputs; vector cblocks; - vector roresources, rwresources; + vector samplers, roresources, rwresources; // VKTODOLOW filter to only functions/resources used by entryPoint @@ -4134,7 +4134,6 @@ void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint, if(ssbo) { - res.IsSampler = false; res.IsReadOnly = false; res.IsTexture = false; res.name = cblock.name; @@ -4208,8 +4207,8 @@ void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint, else if(type->texdim == spv::DimBuffer) res.resType = TextureDim::Buffer; - res.IsSampler = - type->type == SPVTypeData::eSampledImage || type->type == SPVTypeData::eSampler; + bool sepSampler = (type->type == SPVTypeData::eSampler); + res.IsTexture = res.resType != TextureDim::Buffer && type->type != SPVTypeData::eSampler; res.IsReadOnly = true; @@ -4300,7 +4299,9 @@ void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint, // are used RDCASSERT(!bindmap.used || bindmap.bind >= 0); - if(res.IsReadOnly) + if(sepSampler) + samplers.push_back(shaderrespair(bindmap, res)); + else if(res.IsReadOnly) roresources.push_back(shaderrespair(bindmap, res)); else rwresources.push_back(shaderrespair(bindmap, res)); @@ -4444,12 +4445,16 @@ void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint, mapping.InputAttributes[reflection.InputSig[i].regIndex] = (int32_t)i; std::sort(cblocks.begin(), cblocks.end()); + std::sort(samplers.begin(), samplers.end()); std::sort(roresources.begin(), roresources.end()); std::sort(rwresources.begin(), rwresources.end()); create_array_uninit(mapping.ConstantBlocks, cblocks.size()); create_array_uninit(reflection.ConstantBlocks, cblocks.size()); + create_array_uninit(mapping.Samplers, samplers.size()); + create_array_uninit(reflection.Samplers, samplers.size()); + create_array_uninit(mapping.ReadOnlyResources, roresources.size()); create_array_uninit(reflection.ReadOnlyResources, roresources.size()); @@ -4468,6 +4473,18 @@ void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint, reflection.ConstantBlocks[i].bindPoint = (int32_t)i; } + for(size_t i = 0; i < samplers.size(); i++) + { + mapping.Samplers[i] = samplers[i].map; + // fix up any bind points marked with -1. They were sorted to the end + // but from here on we want to just be able to index with the bind point + // without any special casing. + if(mapping.Samplers[i].bind == -1) + mapping.Samplers[i].bind = 0; + reflection.Samplers[i].name = samplers[i].bindres.name; + reflection.Samplers[i].bindPoint = (int32_t)i; + } + for(size_t i = 0; i < roresources.size(); i++) { mapping.ReadOnlyResources[i] = roresources[i].map;