summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2020-12-03 08:23:05 -0800
committerGitHub <noreply@github.com>2020-12-03 08:23:05 -0800
commit44c0a56974b664e50b2cb8cb6f10740b19c4e02f (patch)
treed6141003be376bdb2c0037178b649b6b2aae673e /tools
parentad5dda9261bae63e32bcb914b109fcb5c92faf25 (diff)
Add shader object parameter binding to renderer_test. (#1622)
* Add shader object parameter binding to renderer_test. * remove multiple-definitions.hlsl * Fix cuda implementation. Co-authored-by: Tim Foley <tfoleyNV@users.noreply.github.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/gfx/d3d11/render-d3d11.cpp327
-rw-r--r--tools/gfx/d3d12/render-d3d12.cpp532
-rw-r--r--tools/gfx/open-gl/render-gl.cpp124
-rw-r--r--tools/gfx/render.h24
-rw-r--r--tools/gfx/vulkan/render-vk.cpp138
-rw-r--r--tools/render-test/cpu-compute-util.cpp11
-rw-r--r--tools/render-test/cuda/cuda-compute-util.cpp12
-rw-r--r--tools/render-test/options.cpp4
-rw-r--r--tools/render-test/options.h6
-rw-r--r--tools/render-test/render-test-main.cpp2099
-rw-r--r--tools/render-test/shader-input-layout.cpp17
-rw-r--r--tools/render-test/shader-input-layout.h9
-rw-r--r--tools/render-test/shader-renderer-util.cpp2
-rw-r--r--tools/render-test/shader-renderer-util.h4
-rw-r--r--tools/render-test/slang-support.cpp60
-rw-r--r--tools/render-test/slang-support.h30
16 files changed, 2310 insertions, 1089 deletions
diff --git a/tools/gfx/d3d11/render-d3d11.cpp b/tools/gfx/d3d11/render-d3d11.cpp
index 30c982ab3..6a58501fd 100644
--- a/tools/gfx/d3d11/render-d3d11.cpp
+++ b/tools/gfx/d3d11/render-d3d11.cpp
@@ -1019,6 +1019,11 @@ Result D3D11Renderer::createBufferResource(Resource::Usage initialUsage, const B
}
}
+ if( bufferDesc.Usage == D3D11_USAGE_DYNAMIC )
+ {
+ bufferDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_WRITE;
+ }
+
D3D11_SUBRESOURCE_DATA subResourceData = { 0 };
subResourceData.pSysMem = initData;
@@ -1394,7 +1399,7 @@ void* D3D11Renderer::map(BufferResource* bufferIn, MapFlavor flavor)
mapType = D3D11_MAP_WRITE_DISCARD;
break;
case MapFlavor::HostWrite:
- mapType = D3D11_MAP_WRITE;
+ mapType = D3D11_MAP_WRITE_NO_OVERWRITE;
break;
case MapFlavor::HostRead:
mapType = D3D11_MAP_READ;
@@ -2104,299 +2109,6 @@ Result D3D11Renderer::createDescriptorSet(DescriptorSetLayout* layout, Descripto
}
-#if 0
-BindingState* D3D11Renderer::createBindingState(const BindingState::Desc& bindingStateDesc)
-{
- RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc));
-
- const auto& srcBindings = bindingStateDesc.m_bindings;
- const int numBindings = int(srcBindings.Count());
-
- auto& dstDetails = bindingState->m_bindingDetails;
- dstDetails.SetSize(numBindings);
-
- for (int i = 0; i < numBindings; ++i)
- {
- auto& dstDetail = dstDetails[i];
- const auto& srcBinding = srcBindings[i];
-
- assert(srcBinding.registerRange.isSingle());
-
- switch (srcBinding.bindingType)
- {
- case BindingType::Buffer:
- {
- assert(srcBinding.resource && srcBinding.resource->isBuffer());
-
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
- const BufferResource::Desc& desc = buffer->getDesc();
-
- const int elemSize = bufferDesc.elementSize <= 0 ? 1 : bufferDesc.elementSize;
-
- if (bufferDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
- {
- D3D11_UNORDERED_ACCESS_VIEW_DESC viewDesc;
- memset(&viewDesc, 0, sizeof(viewDesc));
- viewDesc.Buffer.FirstElement = 0;
- viewDesc.Buffer.NumElements = (UINT)(bufferDesc.sizeInBytes / elemSize);
- viewDesc.Buffer.Flags = 0;
- viewDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
- viewDesc.Format = D3DUtil::getMapFormat(bufferDesc.format);
-
- if (bufferDesc.elementSize == 0 && bufferDesc.format == Format::Unknown)
- {
- viewDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_RAW;
- viewDesc.Format = DXGI_FORMAT_R32_TYPELESS;
- }
-
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateUnorderedAccessView(buffer->m_buffer, &viewDesc, dstDetail.m_uav.writeRef()));
- }
- if (bufferDesc.bindFlags & (Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource))
- {
- D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
- memset(&viewDesc, 0, sizeof(viewDesc));
- viewDesc.Buffer.FirstElement = 0;
- viewDesc.Buffer.ElementWidth = elemSize;
- viewDesc.Buffer.NumElements = (UINT)(bufferDesc.sizeInBytes / elemSize);
- viewDesc.Buffer.ElementOffset = 0;
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
- viewDesc.Format = DXGI_FORMAT_UNKNOWN;
-
- if (bufferDesc.elementSize == 0)
- {
- viewDesc.Format = DXGI_FORMAT_R32_FLOAT;
- }
-
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateShaderResourceView(buffer->m_buffer, &viewDesc, dstDetail.m_srv.writeRef()));
- }
- break;
- }
- case BindingType::Texture:
- case BindingType::CombinedTextureSampler:
- {
- assert(srcBinding.resource && srcBinding.resource->isTexture());
-
- TextureResourceImpl* texture = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr());
-
- const TextureResource::Desc& textureDesc = texture->getDesc();
-
- D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
- viewDesc.Format = D3DUtil::getMapFormat(textureDesc.format);
-
- switch (texture->getType())
- {
- case Resource::Type::Texture1D:
- {
- if (textureDesc.arraySize <= 0)
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
- viewDesc.Texture1D.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture1D.MostDetailedMip = 0;
- }
- else
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
- viewDesc.Texture1DArray.ArraySize = textureDesc.arraySize;
- viewDesc.Texture1DArray.FirstArraySlice = 0;
- viewDesc.Texture1DArray.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture1DArray.MostDetailedMip = 0;
- }
- break;
- }
- case Resource::Type::Texture2D:
- {
- if (textureDesc.arraySize <= 0)
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
- viewDesc.Texture2D.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture2D.MostDetailedMip = 0;
- }
- else
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
- viewDesc.Texture2DArray.ArraySize = textureDesc.arraySize;
- viewDesc.Texture2DArray.FirstArraySlice = 0;
- viewDesc.Texture2DArray.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture2DArray.MostDetailedMip = 0;
- }
- break;
- }
- case Resource::Type::TextureCube:
- {
- if (textureDesc.arraySize <= 0)
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
- viewDesc.TextureCube.MipLevels = textureDesc.numMipLevels;
- viewDesc.TextureCube.MostDetailedMip = 0;
- }
- else
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
- viewDesc.TextureCubeArray.MipLevels = textureDesc.numMipLevels;
- viewDesc.TextureCubeArray.MostDetailedMip = 0;
- viewDesc.TextureCubeArray.First2DArrayFace = 0;
- viewDesc.TextureCubeArray.NumCubes = textureDesc.arraySize;
- }
- break;
- }
- case Resource::Type::Texture3D:
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
- viewDesc.Texture3D.MipLevels = textureDesc.numMipLevels; // Old code fixed as one
- viewDesc.Texture3D.MostDetailedMip = 0;
- break;
- }
- default:
- {
- assert(!"Unhandled type");
- return nullptr;
- }
- }
-
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateShaderResourceView(texture->m_resource, &viewDesc, dstDetail.m_srv.writeRef()));
- break;
- }
- case BindingType::Sampler:
- {
- const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex];
-
- D3D11_SAMPLER_DESC desc = {};
- desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
-
- if (samplerDesc.isCompareSampler)
- {
- desc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
- desc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
- desc.MinLOD = desc.MaxLOD = 0.0f;
- }
- else
- {
- desc.Filter = D3D11_FILTER_ANISOTROPIC;
- desc.MaxAnisotropy = 8;
- desc.MinLOD = 0.0f;
- desc.MaxLOD = 100.0f;
- }
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateSamplerState(&desc, dstDetail.m_samplerState.writeRef()));
- break;
- }
- default:
- {
- assert(!"Unhandled type");
- return nullptr;
- }
- }
- }
-
- // Done
- return bindingState.detach();
-}
-
-void D3D11Renderer::_applyBindingState(bool isCompute)
-{
- auto context = m_immediateContext.get();
-
- const auto& details = m_currentBindings->m_bindingDetails;
- const auto& bindings = m_currentBindings->getDesc().m_bindings;
-
- const int numBindings = int(bindings.Count());
-
- for (int i = 0; i < numBindings; ++i)
- {
- const auto& binding = bindings[i];
- const auto& detail = details[i];
-
- const int bindingIndex = binding.registerRange.getSingleIndex();
-
- switch (binding.bindingType)
- {
- case BindingType::Buffer:
- {
- assert(binding.resource && binding.resource->isBuffer());
- if (binding.resource->canBind(Resource::BindFlag::ConstantBuffer))
- {
- ID3D11Buffer* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr())->m_buffer;
- if (isCompute)
- context->CSSetConstantBuffers(bindingIndex, 1, &buffer);
- else
- {
- context->VSSetConstantBuffers(bindingIndex, 1, &buffer);
- context->PSSetConstantBuffers(bindingIndex, 1, &buffer);
- }
- }
- else if (detail.m_uav)
- {
- if (isCompute)
- context->CSSetUnorderedAccessViews(bindingIndex, 1, detail.m_uav.readRef(), nullptr);
- else
- context->OMSetRenderTargetsAndUnorderedAccessViews(
- m_currentBindings->getDesc().m_numRenderTargets,
- m_renderTargetViews.getBuffer()->readRef(),
- m_depthStencilView,
- bindingIndex,
- 1,
- detail.m_uav.readRef(),
- nullptr);
- }
- else
- {
- if (isCompute)
- context->CSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- else
- {
- context->PSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- context->VSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- }
- }
- break;
- }
- case BindingType::Texture:
- {
- if (detail.m_uav)
- {
- if (isCompute)
- context->CSSetUnorderedAccessViews(bindingIndex, 1, detail.m_uav.readRef(), nullptr);
- else
- context->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL,
- nullptr, nullptr, bindingIndex, 1, detail.m_uav.readRef(), nullptr);
- }
- else
- {
- if (isCompute)
- context->CSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- else
- {
- context->PSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- context->VSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- }
- }
- break;
- }
- case BindingType::Sampler:
- {
- if (isCompute)
- context->CSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef());
- else
- {
- context->PSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef());
- context->VSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef());
- }
- break;
- }
- default:
- {
- assert(!"Not implemented");
- return;
- }
- }
- }
-}
-
-void D3D11Renderer::setBindingState(BindingState* state)
-{
- m_currentBindings = static_cast<BindingStateImpl*>(state);
-}
-#endif
-
void D3D11Renderer::_flushGraphicsState()
{
auto pipelineType = int(PipelineType::Graphics);
@@ -2453,22 +2165,37 @@ void D3D11Renderer::DescriptorSetImpl::setResource(UInt range, UInt index, Resou
{
auto viewImpl = (ResourceViewImpl*)view;
auto& rangeInfo = m_layout->m_ranges[range];
+ auto flatIndex = rangeInfo.arrayIndex + index;
switch (rangeInfo.type)
{
case D3D11DescriptorSlotType::ShaderResourceView:
{
- assert(viewImpl->m_type == ResourceViewImpl::Type::SRV);
- auto srvImpl = (ShaderResourceViewImpl*)viewImpl;
- m_srvs[rangeInfo.arrayIndex + index] = srvImpl->m_srv;
+ if( viewImpl )
+ {
+ assert(viewImpl->m_type == ResourceViewImpl::Type::SRV);
+ auto srvImpl = (ShaderResourceViewImpl*)viewImpl;
+ m_srvs[flatIndex] = srvImpl->m_srv;
+ }
+ else
+ {
+ m_srvs[flatIndex] = nullptr;
+ }
}
break;
case D3D11DescriptorSlotType::UnorderedAccessView:
{
- assert(viewImpl->m_type == ResourceViewImpl::Type::UAV);
- auto uavImpl = (UnorderedAccessViewImpl*)viewImpl;
- m_uavs[rangeInfo.arrayIndex + index] = uavImpl->m_uav;
+ if( viewImpl )
+ {
+ assert(viewImpl->m_type == ResourceViewImpl::Type::UAV);
+ auto uavImpl = (UnorderedAccessViewImpl*)viewImpl;
+ m_uavs[flatIndex] = uavImpl->m_uav;
+ }
+ else
+ {
+ m_uavs[flatIndex] = nullptr;
+ }
}
break;
diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp
index 0f23d8dd4..886754f0e 100644
--- a/tools/gfx/d3d12/render-d3d12.cpp
+++ b/tools/gfx/d3d12/render-d3d12.cpp
@@ -1082,270 +1082,6 @@ Result D3D12Renderer::captureTextureToSurface(D3D12Resource& resource, Surface&
}
}
-#if 0
-Result D3D12Renderer::calcComputePipelineState(ComPtr<ID3D12RootSignature>& signatureOut, ComPtr<ID3D12PipelineState>& pipelineStateOut)
-{
- BindParameters bindParameters;
- _calcBindParameters(bindParameters);
-
- ComPtr<ID3D12RootSignature> rootSignature;
- ComPtr<ID3D12PipelineState> pipelineState;
-
- {
- D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc;
- rootSignatureDesc.NumParameters = bindParameters.m_paramIndex;
- rootSignatureDesc.pParameters = bindParameters.m_parameters;
- rootSignatureDesc.NumStaticSamplers = 0;
- rootSignatureDesc.pStaticSamplers = nullptr;
- rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
-
- ComPtr<ID3DBlob> signature;
- ComPtr<ID3DBlob> error;
- SLANG_RETURN_ON_FAIL(m_D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, signature.writeRef(), error.writeRef()));
- SLANG_RETURN_ON_FAIL(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(rootSignature.writeRef())));
- }
-
- {
- // Describe and create the compute pipeline state object
- D3D12_COMPUTE_PIPELINE_STATE_DESC computeDesc = {};
- computeDesc.pRootSignature = rootSignature;
- computeDesc.CS = { m_boundShaderProgram->m_computeShader.getBuffer(), m_boundShaderProgram->m_computeShader.Count() };
- SLANG_RETURN_ON_FAIL(m_device->CreateComputePipelineState(&computeDesc, IID_PPV_ARGS(pipelineState.writeRef())));
- }
-
- signatureOut.swap(rootSignature);
- pipelineStateOut.swap(pipelineState);
-
- return SLANG_OK;
-}
-#endif
-
-#if 0
-D3D12Renderer::RenderState* D3D12Renderer::findRenderState(PipelineType pipelineType)
-{
- switch (pipelineType)
- {
- case PipelineType::Compute:
- {
- // Check if current state is a match
- if (m_currentRenderState)
- {
- if (m_currentRenderState->m_bindingState == m_boundBindingState &&
- m_currentRenderState->m_shaderProgram == m_boundShaderProgram)
- {
- return m_currentRenderState;
- }
- }
-
- const int num = int(m_renderStates.Count());
- for (int i = 0; i < num; i++)
- {
- RenderState* renderState = m_renderStates[i];
- if (renderState->m_bindingState == m_boundBindingState &&
- renderState->m_shaderProgram == m_boundShaderProgram)
- {
- return renderState;
- }
- }
- break;
- }
- case PipelineType::Graphics:
- {
- if (m_currentRenderState)
- {
- if (m_currentRenderState->m_bindingState == m_boundBindingState &&
- m_currentRenderState->m_inputLayout == m_boundInputLayout &&
- m_currentRenderState->m_shaderProgram == m_boundShaderProgram &&
- m_currentRenderState->m_primitiveTopologyType == m_primitiveTopologyType)
- {
- return m_currentRenderState;
- }
- }
- // See if matches one in the list
- {
- const int num = int(m_renderStates.Count());
- for (int i = 0; i < num; i++)
- {
- RenderState* renderState = m_renderStates[i];
- if (renderState->m_bindingState == m_boundBindingState &&
- renderState->m_inputLayout == m_boundInputLayout &&
- renderState->m_shaderProgram == m_boundShaderProgram &&
- renderState->m_primitiveTopologyType == m_primitiveTopologyType)
- {
- // Okay we have a match
- return renderState;
- }
- }
- }
- break;
- }
- default: break;
- }
- return nullptr;
-}
-
-D3D12Renderer::RenderState* D3D12Renderer::calcRenderState()
-{
- if (!m_boundShaderProgram)
- {
- return nullptr;
- }
- m_currentRenderState = findRenderState(m_boundShaderProgram->m_pipelineType);
- if (m_currentRenderState)
- {
- return m_currentRenderState;
- }
-
- ComPtr<ID3D12RootSignature> rootSignature;
- ComPtr<ID3D12PipelineState> pipelineState;
-
- switch (m_boundShaderProgram->m_pipelineType)
- {
- case PipelineType::Compute:
- {
- if (SLANG_FAILED(calcComputePipelineState(rootSignature, pipelineState)))
- {
- return nullptr;
- }
- break;
- }
- case PipelineType::Graphics:
- {
- if (SLANG_FAILED(calcGraphicsPipelineState(rootSignature, pipelineState)))
- {
- return nullptr;
- }
- break;
- }
- default: return nullptr;
- }
-
- RenderState* renderState = new RenderState;
-
- renderState->m_primitiveTopologyType = m_primitiveTopologyType;
- renderState->m_bindingState = m_boundBindingState;
- renderState->m_inputLayout = m_boundInputLayout;
- renderState->m_shaderProgram = m_boundShaderProgram;
-
- renderState->m_rootSignature.swap(rootSignature);
- renderState->m_pipelineState.swap(pipelineState);
-
- m_renderStates.Add(renderState);
-
- m_currentRenderState = renderState;
-
- return renderState;
-}
-
-Result D3D12Renderer::_calcBindParameters(BindParameters& params)
-{
- int numConstantBuffers = 0;
- {
- if (m_boundBindingState)
- {
- const int numBoundConstantBuffers = numConstantBuffers;
-
- const BindingState::Desc& bindingStateDesc = m_boundBindingState->getDesc();
-
- const auto& bindings = bindingStateDesc.m_bindings;
- const auto& details = m_boundBindingState->m_bindingDetails;
-
- const int numBindings = int(bindings.Count());
-
- for (int i = 0; i < numBindings; i++)
- {
- const auto& binding = bindings[i];
- const auto& detail = details[i];
-
- const int bindingIndex = binding.registerRange.getSingleIndex();
-
- if (binding.bindingType == BindingType::Buffer)
- {
- assert(binding.resource && binding.resource->isBuffer());
- if (binding.resource->canBind(Resource::BindFlag::ConstantBuffer))
- {
- // Make sure it's not overlapping the ones we just statically defined
- //assert(binding.m_binding < numBoundConstantBuffers);
-
- D3D12_ROOT_PARAMETER& param = params.nextParameter();
- param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
- param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
-
- D3D12_ROOT_DESCRIPTOR& descriptor = param.Descriptor;
- descriptor.ShaderRegister = bindingIndex;
- descriptor.RegisterSpace = 0;
-
- numConstantBuffers++;
- }
- }
-
- if (detail.m_srvIndex >= 0)
- {
- D3D12_DESCRIPTOR_RANGE& range = params.nextRange();
-
- range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
- range.NumDescriptors = 1;
- range.BaseShaderRegister = bindingIndex;
- range.RegisterSpace = 0;
- range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
-
- D3D12_ROOT_PARAMETER& param = params.nextParameter();
-
- param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
- param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
-
- D3D12_ROOT_DESCRIPTOR_TABLE& table = param.DescriptorTable;
- table.NumDescriptorRanges = 1;
- table.pDescriptorRanges = &range;
- }
-
- if (detail.m_uavIndex >= 0)
- {
- D3D12_DESCRIPTOR_RANGE& range = params.nextRange();
-
- range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
- range.NumDescriptors = 1;
- range.BaseShaderRegister = bindingIndex;
- range.RegisterSpace = 0;
- range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
-
- D3D12_ROOT_PARAMETER& param = params.nextParameter();
-
- param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
- param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
-
- D3D12_ROOT_DESCRIPTOR_TABLE& table = param.DescriptorTable;
- table.NumDescriptorRanges = 1;
- table.pDescriptorRanges = &range;
- }
- }
- }
- }
-
- // All the samplers are in one continuous section of the sampler heap
- if (m_boundBindingState && m_boundBindingState->m_samplerHeap.getUsedSize() > 0)
- {
- D3D12_DESCRIPTOR_RANGE& range = params.nextRange();
-
- range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
- range.NumDescriptors = m_boundBindingState->m_samplerHeap.getUsedSize();
- range.BaseShaderRegister = 0;
- range.RegisterSpace = 0;
- range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
-
- D3D12_ROOT_PARAMETER& param = params.nextParameter();
-
- param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
- param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
-
- D3D12_ROOT_DESCRIPTOR_TABLE& table = param.DescriptorTable;
- table.NumDescriptorRanges = 1;
- table.pDescriptorRanges = &range;
- }
- return SLANG_OK;
-}
-#endif
-
Result D3D12Renderer::_bindRenderState(PipelineStateImpl* pipelineStateImpl, ID3D12GraphicsCommandList* commandList, Submitter* submitter)
{
// TODO: we should only set some of this state as needed...
@@ -2952,176 +2688,6 @@ void D3D12Renderer::dispatchCompute(int x, int y, int z)
commandList->Dispatch(x, y, z);
}
-#if 0
-BindingState* D3D12Renderer::createBindingState(const BindingState::Desc& bindingStateDesc)
-{
- RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc));
-
- SLANG_RETURN_NULL_ON_FAIL(bindingState->init(m_device));
-
- const auto& srcBindings = bindingStateDesc.m_bindings;
- const int numBindings = int(srcBindings.Count());
-
- auto& dstDetails = bindingState->m_bindingDetails;
- dstDetails.SetSize(numBindings);
-
- for (int i = 0; i < numBindings; ++i)
- {
- const auto& srcEntry = srcBindings[i];
- auto& dstDetail = dstDetails[i];
-
- const int bindingIndex = srcEntry.registerRange.getSingleIndex();
-
- switch (srcEntry.bindingType)
- {
- case BindingType::Buffer:
- {
- assert(srcEntry.resource && srcEntry.resource->isBuffer());
- BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcEntry.resource.Ptr());
- const BufferResource::Desc& desc = bufferResource->getDesc();
-
- const size_t bufferSize = bufferDesc.sizeInBytes;
- const int elemSize = bufferDesc.elementSize <= 0 ? sizeof(uint32_t) : bufferDesc.elementSize;
-
- const bool createSrv = false;
-
- // NOTE! In this arrangement the buffer can either be a ConstantBuffer or a 'StorageBuffer'.
- // If it's a storage buffer then it has a 'uav'.
- // In neither circumstance is there an associated srv
- // This departs a little from dx11 code - in that it will create srv and uav for a storage buffer.
- if (bufferDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
- {
- dstDetail.m_uavIndex = bindingState->m_viewHeap.allocate();
- if (dstDetail.m_uavIndex < 0)
- {
- return nullptr;
- }
-
- D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
-
- uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
- uavDesc.Format = D3DUtil::getMapFormat(bufferDesc.format);
-
- uavDesc.Buffer.StructureByteStride = elemSize;
-
- uavDesc.Buffer.FirstElement = 0;
- uavDesc.Buffer.NumElements = (UINT)(bufferSize / elemSize);
- uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
-
- if (bufferDesc.elementSize == 0 && bufferDesc.format == Format::Unknown)
- {
- uavDesc.Buffer.Flags |= D3D12_BUFFER_UAV_FLAG_RAW;
- uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
-
- uavDesc.Buffer.StructureByteStride = 0;
- }
- else if( bufferDesc.format != Format::Unknown )
- {
- uavDesc.Buffer.StructureByteStride = 0;
- }
-
- m_device->CreateUnorderedAccessView(bufferResource->m_resource, nullptr, &uavDesc, bindingState->m_viewHeap.getCpuHandle(dstDetail.m_uavIndex));
- }
- if (createSrv && (bufferDesc.bindFlags & (Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource)))
- {
- dstDetail.m_srvIndex = bindingState->m_viewHeap.allocate();
- if (dstDetail.m_srvIndex < 0)
- {
- return nullptr;
- }
-
- D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
-
- srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
- srvDesc.Format = DXGI_FORMAT_UNKNOWN;
- srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
-
- srvDesc.Buffer.FirstElement = 0;
- srvDesc.Buffer.NumElements = (UINT)(bufferSize / elemSize);
- srvDesc.Buffer.StructureByteStride = elemSize;
- srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
-
- if (bufferDesc.elementSize == 0)
- {
- srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
- }
-
- m_device->CreateShaderResourceView(bufferResource->m_resource, &srvDesc, bindingState->m_viewHeap.getCpuHandle(dstDetail.m_srvIndex));
- }
-
- break;
- }
- case BindingType::Texture:
- {
- assert(srcEntry.resource && srcEntry.resource->isTexture());
-
- TextureResourceImpl* textureResource = static_cast<TextureResourceImpl*>(srcEntry.resource.Ptr());
-
- dstDetail.m_srvIndex = bindingState->m_viewHeap.allocate();
- if (dstDetail.m_srvIndex < 0)
- {
- return nullptr;
- }
-
- {
- const D3D12_RESOURCE_DESC resourceDesc = textureResource->m_resource.getResource()->GetDesc();
- const DXGI_FORMAT pixelFormat = resourceDesc.Format;
-
- D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
- _initSrvDesc(textureResource->getType(), textureResource->getDesc(), resourceDesc, pixelFormat, srvDesc);
-
- // Create descriptor
- m_device->CreateShaderResourceView(textureResource->m_resource, &srvDesc, bindingState->m_viewHeap.getCpuHandle(dstDetail.m_srvIndex));
- }
-
- break;
- }
- case BindingType::Sampler:
- {
- const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcEntry.descIndex];
-
- const int samplerIndex = bindingIndex;
- dstDetail.m_samplerIndex = samplerIndex;
- bindingState->m_samplerHeap.placeAt(samplerIndex);
-
- D3D12_SAMPLER_DESC desc = {};
- desc.AddressU = desc.AddressV = desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
- desc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
-
- if (samplerDesc.isCompareSampler)
- {
- desc.ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
- desc.Filter = D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
- }
- else
- {
- desc.Filter = D3D12_FILTER_ANISOTROPIC;
- desc.MaxAnisotropy = 8;
- desc.MinLOD = 0.0f;
- desc.MaxLOD = 100.0f;
- }
-
- m_device->CreateSampler(&desc, bindingState->m_samplerHeap.getCpuHandle(samplerIndex));
-
- break;
- }
- case BindingType::CombinedTextureSampler:
- {
- assert(!"Not implemented");
- return nullptr;
- }
- }
- }
-
- return bindingState.detach();
-}
-
-void D3D12Renderer::setBindingState(BindingState* state)
-{
- m_boundBindingState = static_cast<BindingStateImpl*>(state);
-}
-#endif
-
void D3D12Renderer::DescriptorSetImpl::setConstantBuffer(UInt range, UInt index, BufferResource* buffer)
{
auto dxDevice = m_renderer->m_device;
@@ -3525,10 +3091,10 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
// Finally, we will go through and fill in ready-to-go D3D
// register range information.
{
- UInt cbvCounter = 0;
- UInt srvCounter = 0;
- UInt uavCounter = 0;
- UInt samplerCounter = 0;
+ UInt cbvRegisterCounter = 0;
+ UInt srvRegisterCounter = 0;
+ UInt uavRegisterCounter = 0;
+ UInt samplerRegisterCounter = 0;
Int resourceRangeCounter = 0;
Int samplerRangeCounter = 0;
@@ -3548,7 +3114,6 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
Int dxRangeIndex = -1;
Int dxPairedSamplerRangeIndex = -1;
-
switch(rangeDesc.type)
{
default:
@@ -3586,7 +3151,12 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
// so that this range doesn't turn into a descriptor
// range in one of the D3D12 descriptor tables.
//
- UInt bindingIndex = cbvCounter; cbvCounter += bindingCount;
+ Int dxRegister = rangeDesc.binding;
+ if( dxRegister < 0 )
+ {
+ dxRegister = cbvRegisterCounter;
+ }
+ cbvRegisterCounter = dxRegister + bindingCount;
auto rootConstantRangeIndex = descriptorSetLayoutImpl->m_ranges[rr].arrayIndex;
auto rootParamIndex = descriptorSetLayoutImpl->m_rootConstantRanges[rootConstantRangeIndex].rootParamIndex;
@@ -3598,7 +3168,7 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
//
auto& dxRootParam = descriptorSetLayoutImpl->m_dxRootParameters[rootParamIndex];
dxRootParam.Constants.RegisterSpace = UINT(bindingSpace);
- dxRootParam.Constants.ShaderRegister = UINT(bindingIndex);
+ dxRootParam.Constants.ShaderRegister = UINT(dxRegister);
continue;
}
break;
@@ -3607,6 +3177,8 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
D3D12_DESCRIPTOR_RANGE& dxRange = descriptorSetLayoutImpl->m_dxRanges[dxRangeIndex];
memset(&dxRange, 0, sizeof(dxRange));
+ Int dxRegister = rangeDesc.binding;
+
switch(rangeDesc.type)
{
default:
@@ -3615,11 +3187,15 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
case DescriptorSlotType::Sampler:
{
- UInt bindingIndex = samplerCounter; samplerCounter += bindingCount;
+ if( dxRegister < 0 )
+ {
+ dxRegister = samplerRegisterCounter;
+ }
+ samplerRegisterCounter = dxRegister + bindingCount;
dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
dxRange.NumDescriptors = UINT(bindingCount);
- dxRange.BaseShaderRegister = UINT(bindingIndex);
+ dxRange.BaseShaderRegister = UINT(dxRegister);
dxRange.RegisterSpace = UINT(bindingSpace);
dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
@@ -3628,11 +3204,15 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
case DescriptorSlotType::SampledImage:
case DescriptorSlotType::UniformTexelBuffer:
{
- UInt bindingIndex = srvCounter; srvCounter += bindingCount;
+ if( dxRegister < 0 )
+ {
+ dxRegister = srvRegisterCounter;
+ }
+ srvRegisterCounter = dxRegister + bindingCount;
dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
dxRange.NumDescriptors = UINT(bindingCount);
- dxRange.BaseShaderRegister = UINT(bindingIndex);
+ dxRange.BaseShaderRegister = UINT(dxRegister);
dxRange.RegisterSpace = UINT(bindingSpace);
dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
@@ -3642,15 +3222,31 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
{
// The combined texture/sampler case basically just
// does the work of both the SRV and sampler cases above.
+ //
+ // TODO(tfoley): The current API for passing down an
+ // explicit register/binding can't handle the requirement
+ // that we specify *two* registers/bindings for the
+ // combined image/sampler case.
+ //
+ // Realistically, the `Renderer` implementation for
+ // targes that don't support combined texture/sampler
+ // bindings should just error out when a client attempts
+ // to create a descriptor set that uses them (rather than
+ // the current behavior which adds a lot of complexity
+ // in the name of trying to make them work).
{
// Here's the SRV logic:
-
- UInt bindingIndex = srvCounter; srvCounter += bindingCount;
+ Int srvRegister = dxRegister;
+ if( srvRegister < 0 )
+ {
+ srvRegister = srvRegisterCounter;
+ }
+ srvRegisterCounter = srvRegister + bindingCount;
dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
dxRange.NumDescriptors = UINT(bindingCount);
- dxRange.BaseShaderRegister = UINT(bindingIndex);
+ dxRange.BaseShaderRegister = UINT(srvRegister);
dxRange.RegisterSpace = UINT(bindingSpace);
dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
@@ -3660,11 +3256,16 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
D3D12_DESCRIPTOR_RANGE& dxPairedSamplerRange = descriptorSetLayoutImpl->m_dxRanges[dxPairedSamplerRangeIndex];
memset(&dxPairedSamplerRange, 0, sizeof(dxPairedSamplerRange));
- UInt pairedSamplerBindingIndex = srvCounter; srvCounter += bindingCount;
+ Int samplerRegister = dxRegister;
+ if( samplerRegister < 0 )
+ {
+ samplerRegister = samplerRegisterCounter;
+ }
+ samplerRegisterCounter = samplerRegister + bindingCount;
dxPairedSamplerRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
dxPairedSamplerRange.NumDescriptors = UINT(bindingCount);
- dxPairedSamplerRange.BaseShaderRegister = UINT(pairedSamplerBindingIndex);
+ dxPairedSamplerRange.BaseShaderRegister = UINT(samplerRegister);
dxPairedSamplerRange.RegisterSpace = UINT(bindingSpace);
dxPairedSamplerRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
@@ -3679,11 +3280,15 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
case DescriptorSlotType::StorageBuffer:
case DescriptorSlotType::DynamicStorageBuffer:
{
- UInt bindingIndex = uavCounter; uavCounter += bindingCount;
+ if( dxRegister < 0 )
+ {
+ dxRegister = uavRegisterCounter;
+ }
+ uavRegisterCounter = dxRegister + bindingCount;
dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
dxRange.NumDescriptors = UINT(bindingCount);
- dxRange.BaseShaderRegister = UINT(bindingIndex);
+ dxRange.BaseShaderRegister = UINT(dxRegister);
dxRange.RegisterSpace = UINT(bindingSpace);
dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
@@ -3692,15 +3297,23 @@ Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc&
case DescriptorSlotType::UniformBuffer:
case DescriptorSlotType::DynamicUniformBuffer:
{
- UInt bindingIndex = cbvCounter; cbvCounter += bindingCount;
+ if( dxRegister < 0 )
+ {
+ dxRegister = cbvRegisterCounter;
+ }
+ cbvRegisterCounter = dxRegister + bindingCount;
dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
dxRange.NumDescriptors = UINT(bindingCount);
- dxRange.BaseShaderRegister = UINT(bindingIndex);
+ dxRange.BaseShaderRegister = UINT(dxRegister);
dxRange.RegisterSpace = UINT(bindingSpace);
dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
break;
+
+
+
+
}
}
}
@@ -3722,6 +3335,8 @@ Result D3D12Renderer::createPipelineLayout(const PipelineLayout::Desc& desc, Pip
auto descriptorSetCount = desc.descriptorSetCount;
+ Int spaceCounter = 0;
+
// We are going to make two passes over the descriptor set layouts
// that are being used to build the pipeline layout. In the first
// pass we will collect all the descriptor ranges that have been
@@ -3740,7 +3355,12 @@ Result D3D12Renderer::createPipelineLayout(const PipelineLayout::Desc& desc, Pip
// that comes from multiple spaces (e.g., if it contains an unbounded
// array).
//
- UInt bindingSpace = dd;
+ Int space = descriptorSetInfo.space;
+ if( space < 0 )
+ {
+ space = spaceCounter;
+ }
+ spaceCounter = space+1;
// Copy descriptor range information from the set layout into our
// temporary copy (this is required because the same set layout
@@ -3754,7 +3374,7 @@ Result D3D12Renderer::createPipelineLayout(const PipelineLayout::Desc& desc, Pip
{
auto& range = ranges[rangeCount++];
range = setDescriptorRange;
- range.RegisterSpace = UINT(bindingSpace);
+ range.RegisterSpace = UINT(space);
// HACK: in order to deal with SM5.0 shaders, `u` registers
// in `space0` need to start with a number *after* the number
diff --git a/tools/gfx/open-gl/render-gl.cpp b/tools/gfx/open-gl/render-gl.cpp
index caf8794c0..bf873212c 100644
--- a/tools/gfx/open-gl/render-gl.cpp
+++ b/tools/gfx/open-gl/render-gl.cpp
@@ -1151,130 +1151,6 @@ void GLRenderer::dispatchCompute(int x, int y, int z)
glDispatchCompute(x, y, z);
}
-#if 0
-BindingState* GLRenderer::createBindingState(const BindingState::Desc& bindingStateDesc)
-{
- RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc, this));
-
- const auto& srcBindings = bindingStateDesc.m_bindings;
- const int numBindings = int(srcBindings.Count());
-
- auto& dstDetails = bindingState->m_bindingDetails;
- dstDetails.SetSize(numBindings);
-
- for (int i = 0; i < numBindings; ++i)
- {
- auto& dstDetail = dstDetails[i];
- const auto& srcBinding = srcBindings[i];
-
-
- switch (srcBinding.bindingType)
- {
- case BindingType::Texture:
- case BindingType::Buffer:
- {
- break;
- }
- case BindingType::CombinedTextureSampler:
- {
- assert(srcBinding.resource && srcBinding.resource->isTexture());
- TextureResourceImpl* texture = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr());
- const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex];
-
- if (samplerDesc.isCompareSampler)
- {
- auto target = texture->m_target;
-
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
- glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
- }
- break;
- }
- case BindingType::Sampler:
- {
- const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex];
-
- GLuint handle;
-
- glCreateSamplers(1, &handle);
- glSamplerParameteri(handle, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glSamplerParameteri(handle, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glSamplerParameteri(handle, GL_TEXTURE_WRAP_R, GL_REPEAT);
-
- if (samplerDesc.isCompareSampler)
- {
- glSamplerParameteri(handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glSamplerParameteri(handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glSamplerParameteri(handle, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
- glSamplerParameteri(handle, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
- }
- else
- {
- glSamplerParameteri(handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- glSamplerParameteri(handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glSamplerParameteri(handle, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8);
- }
-
- dstDetail.m_samplerHandle = handle;
- break;
- }
- }
- }
-
- return bindingState.detach();
-}
-
-void GLRenderer::setBindingState(BindingState* stateIn)
-{
- BindingStateImpl* state = static_cast<BindingStateImpl*>(stateIn);
-
- const auto& bindingDesc = state->getDesc();
-
- const auto& details = state->m_bindingDetails;
- const auto& bindings = bindingDesc.m_bindings;
- const int numBindings = int(bindings.Count());
-
- for (int i = 0; i < numBindings; ++i)
- {
- const auto& binding = bindings[i];
- const auto& detail = details[i];
-
- switch (binding.bindingType)
- {
- case BindingType::Buffer:
- {
- const int bindingIndex = binding.registerRange.getSingleIndex();
-
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr());
- glBindBufferBase(buffer->m_target, bindingIndex, buffer->m_handle);
- break;
- }
- case BindingType::Sampler:
- {
- for (int index = binding.registerRange.index; index < binding.registerRange.index + binding.registerRange.size; ++index)
- {
- glBindSampler(index, detail.m_samplerHandle);
- }
- break;
- }
- case BindingType::Texture:
- case BindingType::CombinedTextureSampler:
- {
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr());
-
- const int bindingIndex = binding.registerRange.getSingleIndex();
-
- glActiveTexture(GL_TEXTURE0 + bindingIndex);
- glBindTexture(buffer->m_target, buffer->m_handle);
- break;
- }
- }
- }
-}
-#endif
-
void GLRenderer::DescriptorSetImpl::setConstantBuffer(UInt range, UInt index, BufferResource* buffer)
{
auto resourceImpl = (BufferResourceImpl*) buffer;
diff --git a/tools/gfx/render.h b/tools/gfx/render.h
index 55beb5774..5ad338594 100644
--- a/tools/gfx/render.h
+++ b/tools/gfx/render.h
@@ -520,6 +520,8 @@ enum class DescriptorSlotType
DynamicStorageBuffer,
InputAttachment,
RootConstant,
+ InlineUniformBlock,
+ RayTracingAccelerationStructure,
};
class DescriptorSetLayout : public Slang::RefObject
@@ -530,6 +532,17 @@ public:
DescriptorSlotType type = DescriptorSlotType::Unknown;
UInt count = 1;
+ /// The underlying API-specific binding/register to use for this slot range.
+ ///
+ /// A value of `-1` indicates that the implementation should
+ /// automatically compute the binding/register to use
+ /// based on the preceeding slot range(s).
+ ///
+ /// Some implementations do not have a concept of bindings/regsiters
+ /// for slot ranges, and will ignore this field.
+ ///
+ Int binding = -1;
+
SlotRangeDesc()
{}
@@ -555,6 +568,17 @@ public:
{
DescriptorSetLayout* layout = nullptr;
+ /// The underlying API-specific space/set number to use for this set.
+ ///
+ /// A value of `-1` indicates that the implementation should
+ /// automatically compute the space/set to use basd on
+ /// the preceeding set(s)
+ ///
+ /// Some implementations do not have a concept of space/set numbers
+ /// for descriptor sets, and will ignore this field.
+ ///
+ Int space = -1;
+
DescriptorSetDesc()
{}
diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp
index 397d657a4..6f2411f24 100644
--- a/tools/gfx/vulkan/render-vk.cpp
+++ b/tools/gfx/vulkan/render-vk.cpp
@@ -2270,144 +2270,6 @@ static VkImageViewType _calcImageViewType(TextureResource::Type type, const Text
return VK_IMAGE_VIEW_TYPE_MAX_ENUM;
}
-#if 0
-BindingState* VKRenderer::createBindingState(const BindingState::Desc& bindingStateDesc)
-{
- RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc, &m_api));
-
- const auto& srcBindings = bindingStateDesc.m_bindings;
- const int numBindings = int(srcBindings.Count());
-
- auto& dstDetails = bindingState->m_bindingDetails;
- dstDetails.SetSize(numBindings);
-
- for (int i = 0; i < numBindings; ++i)
- {
- auto& dstDetail = dstDetails[i];
- const auto& srcBinding = srcBindings[i];
-
- switch (srcBinding.bindingType)
- {
- case BindingType::Buffer:
- {
- if (!srcBinding.resource || !srcBinding.resource->isBuffer())
- {
- assert(!"Needs to have a buffer resource set");
- return nullptr;
- }
-
- BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
- const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc();
-
- if (bufferResourceDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
- {
- // VkBufferView uav
-
- VkBufferViewCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO };
-
- info.format = VK_FORMAT_R32_SFLOAT;
- // TODO:
- // Not sure how to handle typeless?
- if (bufferResourceDesc.elementSize == 0)
- {
- info.format = VK_FORMAT_R32_SFLOAT; // DXGI_FORMAT_R32_TYPELESS ?
- }
-
- info.buffer = bufferResource->m_buffer.m_buffer;
- info.offset = 0;
- info.range = bufferResourceDesc.sizeInBytes;
-
- SLANG_VK_RETURN_NULL_ON_FAIL(m_api.vkCreateBufferView(m_device, &info, nullptr, &dstDetail.m_uav));
- }
-
- // TODO: Setup views.
- // VkImageView srv
-
-
- break;
- }
- case BindingType::Sampler:
- {
- VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
-
- samplerInfo.magFilter = VK_FILTER_LINEAR;
- samplerInfo.minFilter = VK_FILTER_LINEAR;
-
- samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
- samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
- samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
-
- samplerInfo.anisotropyEnable = VK_FALSE;
- samplerInfo.maxAnisotropy = 1;
-
- samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
- samplerInfo.unnormalizedCoordinates = VK_FALSE;
- samplerInfo.compareEnable = VK_FALSE;
- samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
- samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
-
- SLANG_VK_RETURN_NULL_ON_FAIL(m_api.vkCreateSampler(m_device, &samplerInfo, nullptr, &dstDetail.m_sampler));
-
- break;
- }
- case BindingType::Texture:
- {
- if (!srcBinding.resource || !srcBinding.resource->isTexture())
- {
- assert(!"Needs to have a texture resource set");
- return nullptr;
- }
-
- TextureResourceImpl* textureResource = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr());
- const TextureResource::Desc& texDesc = textureResource->getDesc();
-
- VkImageViewType imageViewType = _calcImageViewType(textureResource->getType(), texDesc);
- if (imageViewType == VK_IMAGE_VIEW_TYPE_MAX_ENUM)
- {
- assert(!"Invalid view type");
- return nullptr;
- }
- const VkFormat format = VulkanUtil::getVkFormat(texDesc.format);
- if (format == VK_FORMAT_UNDEFINED)
- {
- assert(!"Unhandled image format");
- return nullptr;
- }
-
- // Create the image view
-
- VkImageViewCreateInfo viewInfo = {};
- viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- viewInfo.image = textureResource->m_image;
- viewInfo.viewType = imageViewType;
- viewInfo.format = format;
- viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- viewInfo.subresourceRange.baseMipLevel = 0;
- viewInfo.subresourceRange.levelCount = 1;
- viewInfo.subresourceRange.baseArrayLayer = 0;
- viewInfo.subresourceRange.layerCount = 1;
-
- viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
- viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
- viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
- viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
-
- SLANG_VK_RETURN_NULL_ON_FAIL(m_api.vkCreateImageView(m_device, &viewInfo, nullptr, &dstDetail.m_srv));
-
- break;
- }
- case BindingType::CombinedTextureSampler:
- {
- assert(!"not implemented");
- return nullptr;
- }
- }
- }
-
- return bindingState.detach();;
-}
-#endif
-
static VkDescriptorType translateDescriptorType(DescriptorSlotType type)
{
switch(type)
diff --git a/tools/render-test/cpu-compute-util.cpp b/tools/render-test/cpu-compute-util.cpp
index 72e44fb78..7c9103cb3 100644
--- a/tools/render-test/cpu-compute-util.cpp
+++ b/tools/render-test/cpu-compute-util.cpp
@@ -420,8 +420,9 @@ SlangResult CPUComputeUtil::fillRuntimeHandleInBuffers(
Context& context,
ISlangSharedLibrary* sharedLib)
{
+ auto request = compilationAndLayout.output.getRequestForReflection();
Slang::ComPtr<slang::ISession> linkage;
- spCompileRequest_getSession(compilationAndLayout.output.request, linkage.writeRef());
+ spCompileRequest_getSession(request, linkage.writeRef());
auto& inputLayout = compilationAndLayout.layout;
for (auto& entry : inputLayout.entries)
{
@@ -433,7 +434,7 @@ SlangResult CPUComputeUtil::fillRuntimeHandleInBuffers(
case RTTIDataEntryType::RTTIObject:
{
auto reflection =
- slang::ShaderReflection::get(compilationAndLayout.output.request);
+ slang::ShaderReflection::get(request);
auto concreteType = reflection->findTypeByName(rtti.typeName.getBuffer());
ComPtr<ISlangBlob> outName;
linkage->getTypeRTTIMangledName(concreteType, outName.writeRef());
@@ -444,7 +445,7 @@ SlangResult CPUComputeUtil::fillRuntimeHandleInBuffers(
break;
case RTTIDataEntryType::WitnessTable:
{
- auto reflection = slang::ShaderReflection::get(compilationAndLayout.output.request);
+ auto reflection = slang::ShaderReflection::get(request);
auto concreteType = reflection->findTypeByName(rtti.typeName.getBuffer());
if (!concreteType)
return SLANG_FAIL;
@@ -503,7 +504,7 @@ SlangResult CPUComputeUtil::fillRuntimeHandleInBuffers(
/* static */SlangResult CPUComputeUtil::calcBindings(const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& outContext)
{
- auto request = compilationAndLayout.output.request;
+ auto request = compilationAndLayout.output.getRequestForReflection();
auto reflection = (slang::ShaderReflection*) spGetReflection(request);
const auto& sourcePath = compilationAndLayout.sourcePath;
@@ -684,7 +685,7 @@ SlangResult CPUComputeUtil::fillRuntimeHandleInBuffers(
/* static */SlangResult CPUComputeUtil::calcExecuteInfo(ExecuteStyle style, ISlangSharedLibrary* sharedLib, const uint32_t dispatchSize[3], const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& context, ExecuteInfo& out)
{
- auto request = compilationAndLayout.output.request;
+ auto request = compilationAndLayout.output.getRequestForReflection();
auto reflection = (slang::ShaderReflection*) spGetReflection(request);
slang::EntryPointReflection* entryPoint = nullptr;
diff --git a/tools/render-test/cuda/cuda-compute-util.cpp b/tools/render-test/cuda/cuda-compute-util.cpp
index cc84d4a00..ea7dab163 100644
--- a/tools/render-test/cuda/cuda-compute-util.cpp
+++ b/tools/render-test/cuda/cuda-compute-util.cpp
@@ -1000,7 +1000,7 @@ static SlangResult _invokeComputeProgram(
const uint32_t dispatchSize[3],
CUDAComputeUtil::Context& outContext)
{
- auto reflection = slang::ProgramLayout::get(outputAndLayout.output.request);
+ auto reflection = slang::ProgramLayout::get(outputAndLayout.output.getRequestForReflection());
auto& bindSet = outContext.m_bindSet;
auto& bindRoot = outContext.m_bindRoot;
@@ -1403,7 +1403,7 @@ static SlangResult _fillRuntimeHandlesInBuffers(
ScopeCUDAModule& cudaModule)
{
Slang::ComPtr<slang::ISession> linkage;
- spCompileRequest_getSession(compilationAndLayout.output.request, linkage.writeRef());
+ spCompileRequest_getSession(compilationAndLayout.output.getRequestForReflection(), linkage.writeRef());
auto& inputLayout = compilationAndLayout.layout;
for (auto& entry : inputLayout.entries)
{
@@ -1415,7 +1415,7 @@ static SlangResult _fillRuntimeHandlesInBuffers(
case RTTIDataEntryType::RTTIObject:
{
auto reflection =
- slang::ShaderReflection::get(compilationAndLayout.output.request);
+ slang::ShaderReflection::get(compilationAndLayout.output.getRequestForReflection());
auto concreteType = reflection->findTypeByName(rtti.typeName.getBuffer());
ComPtr<ISlangBlob> outName;
linkage->getTypeRTTIMangledName(concreteType, outName.writeRef());
@@ -1431,7 +1431,7 @@ static SlangResult _fillRuntimeHandlesInBuffers(
case RTTIDataEntryType::WitnessTable:
{
auto reflection =
- slang::ShaderReflection::get(compilationAndLayout.output.request);
+ slang::ShaderReflection::get(compilationAndLayout.output.getRequestForReflection());
auto concreteType = reflection->findTypeByName(rtti.typeName.getBuffer());
if (!concreteType)
return SLANG_FAIL;
@@ -1527,7 +1527,7 @@ static SlangResult _setUpArguments(
const uint32_t dispatchSize[3],
CUDAComputeUtil::Context& outContext)
{
- auto reflection = slang::ProgramLayout::get(outputAndLayout.output.request);
+ auto reflection = slang::ProgramLayout::get(outputAndLayout.output.getRequestForReflection());
auto& bindSet = outContext.m_bindSet;
auto& bindRoot = outContext.m_bindRoot;
@@ -1835,7 +1835,7 @@ SlangResult _loadAndInvokeKernel(
auto& bindSet = outContext.m_bindSet;
auto& bindRoot = outContext.m_bindRoot;
- auto request = outputAndLayout.output.request;
+ auto request = outputAndLayout.output.getRequestForReflection();
auto reflection = (slang::ShaderReflection*) spGetReflection(request);
// Load cuda module first so its symbols may be queried and filled into argument buffers.
diff --git a/tools/render-test/options.cpp b/tools/render-test/options.cpp
index 797439cfa..100c353e0 100644
--- a/tools/render-test/options.cpp
+++ b/tools/render-test/options.cpp
@@ -250,6 +250,10 @@ static SlangResult _setRendererType(RendererType type, const char* arg, Slang::W
outOptions.nvapiExtnSlot = (*argCursor++);
}
+ else if (strcmp(arg, "-shaderobj") == 0)
+ {
+ outOptions.useShaderObjects = true;
+ }
else
{
// Lookup
diff --git a/tools/render-test/options.h b/tools/render-test/options.h
index ddb903a4a..646cf3a76 100644
--- a/tools/render-test/options.h
+++ b/tools/render-test/options.h
@@ -3,6 +3,10 @@
#include <stdint.h>
+#ifndef SLANG_HANDLE_RESULT_FAIL
+#define SLANG_HANDLE_RESULT_FAIL(x) assert(!"failure")
+#endif
+
#include "../../slang-com-helper.h"
#include "../../source/core/slang-writer.h"
@@ -63,6 +67,8 @@ struct Options
bool useDXIL = false;
bool onlyStartup = false;
+ bool useShaderObjects = false;
+
bool performanceProfile = false;
bool dontAddDefaultEntryPoints = false;
diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp
index f6f3e4ce6..197ee2b46 100644
--- a/tools/render-test/render-test-main.cpp
+++ b/tools/render-test/render-test-main.cpp
@@ -67,60 +67,1865 @@ static void _outputProfileTime(uint64_t startTicks, uint64_t endTicks)
out.print("profile-time=%g\n", time);
}
-class RenderTestApp : public WindowListener
+class ProgramVars;
+
+struct ShaderOutputPlan
{
- public:
+ struct Item
+ {
+ Index inputLayoutEntryIndex;
+ RefPtr<Resource> resource;
+ };
+ List<Item> items;
+};
+
+class RenderTestApp : public WindowListener
+{
+public:
// WindowListener
virtual Result update(Window* window) SLANG_OVERRIDE;
- // At initialization time, we are going to load and compile our Slang shader
- // code, and then create the API objects we need for rendering.
- Result initialize(SlangSession* session, Renderer* renderer, const Options& options, const ShaderCompilerUtil::Input& input);
+ // At initialization time, we are going to load and compile our Slang shader
+ // code, and then create the API objects we need for rendering.
+ virtual Result initialize(
+ SlangSession* session,
+ Renderer* renderer,
+ const Options& options,
+ const ShaderCompilerUtil::Input& input) = 0;
void runCompute();
void renderFrame();
void finalize();
- BindingStateImpl* getBindingState() const { return m_bindingState; }
-
- Result writeBindingOutput(BindRoot* bindRoot, const char* fileName);
+ virtual void applyBinding(PipelineType pipelineType) = 0;
+ virtual void setProjectionMatrix() = 0;
+ virtual Result writeBindingOutput(BindRoot* bindRoot, const char* fileName) = 0;
Result writeScreen(const char* filename);
- protected:
- /// Called in initialize
- Result _initializeShaders(SlangSession* session, Renderer* renderer, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input);
+protected:
+ /// Called in initialize
+ Result _initializeShaders(
+ SlangSession* session,
+ Renderer* renderer,
+ Options::ShaderProgramType shaderType,
+ const ShaderCompilerUtil::Input& input);
uint64_t m_startTicks;
- // variables for state to be used for rendering...
- uintptr_t m_constantBufferSize;
+ // variables for state to be used for rendering...
+ uintptr_t m_constantBufferSize;
- RefPtr<Renderer> m_renderer;
+ RefPtr<Renderer> m_renderer;
- RefPtr<BufferResource> m_constantBuffer;
- RefPtr<InputLayout> m_inputLayout;
- RefPtr<BufferResource> m_vertexBuffer;
- RefPtr<ShaderProgram> m_shaderProgram;
- RefPtr<PipelineState> m_pipelineState;
- RefPtr<BindingStateImpl> m_bindingState;
+ RefPtr<InputLayout> m_inputLayout;
+ RefPtr<BufferResource> m_vertexBuffer;
+ RefPtr<ShaderProgram> m_shaderProgram;
+ RefPtr<PipelineState> m_pipelineState;
ShaderCompilerUtil::OutputAndLayout m_compilationOutput;
- ShaderInputLayout m_shaderInputLayout; ///< The binding layout
- int m_numAddedConstantBuffers; ///< Constant buffers can be added to the binding directly. Will be added at the end.
+ ShaderInputLayout m_shaderInputLayout; ///< The binding layout
Options m_options;
};
-SlangResult RenderTestApp::initialize(SlangSession* session, Renderer* renderer, const Options& options, const ShaderCompilerUtil::Input& input)
+class LegacyRenderTestApp : public RenderTestApp
+{
+public:
+ virtual void applyBinding(PipelineType pipelineType) SLANG_OVERRIDE;
+ virtual void setProjectionMatrix() SLANG_OVERRIDE;
+ virtual Result initialize(
+ SlangSession* session,
+ Renderer* renderer,
+ const Options& options,
+ const ShaderCompilerUtil::Input& input) SLANG_OVERRIDE;
+
+ BindingStateImpl* getBindingState() const { return m_bindingState; }
+
+ virtual Result writeBindingOutput(BindRoot* bindRoot, const char* fileName) override;
+
+protected:
+ uintptr_t m_constantBufferSize;
+ RefPtr<BufferResource> m_constantBuffer;
+ RefPtr<BindingStateImpl> m_bindingState;
+ int m_numAddedConstantBuffers; ///< Constant buffers can be added to the binding directly. Will be added at the end.
+};
+
+class ShaderObjectRenderTestApp : public RenderTestApp
+{
+public:
+ virtual void applyBinding(PipelineType pipelineType) SLANG_OVERRIDE;
+ virtual void setProjectionMatrix() SLANG_OVERRIDE;
+ virtual Result initialize(
+ SlangSession* session,
+ Renderer* renderer,
+ const Options& options,
+ const ShaderCompilerUtil::Input& input) SLANG_OVERRIDE;
+ virtual Result writeBindingOutput(BindRoot* bindRoot, const char* fileName) override;
+
+protected:
+ RefPtr<ProgramVars> m_programVars;
+ ShaderOutputPlan m_outputPlan;
+};
+
+struct ShaderOffset
+{
+ SlangInt uniformOffset = 0;
+ SlangInt bindingRangeIndex = 0;
+ SlangInt bindingArrayIndex = 0;
+};
+
+class ShaderObjectLayout : public RefObject
+{
+public:
+ struct BindingRangeInfo
+ {
+ slang::BindingType bindingType;
+ Index count;
+ Index baseIndex;
+ Index descriptorSetIndex;
+ Index rangeIndexInDescriptorSet;
+// Index subObjectRangeIndex = -1;
+ };
+
+ struct SubObjectRangeInfo
+ {
+ RefPtr<ShaderObjectLayout> layout;
+// Index baseIndex;
+// Index count;
+ Index bindingRangeIndex;
+ };
+
+ struct DescriptorSetInfo : public RefObject
+ {
+ RefPtr<DescriptorSetLayout> layout;
+ Slang::Int space = -1;
+ };
+
+ struct Builder
+ {
+ public:
+ Builder(Renderer* renderer)
+ : m_renderer(renderer)
+ {}
+
+ List<BindingRangeInfo> m_bindingRanges;
+ List<SubObjectRangeInfo> m_subObjectRanges;
+
+ Index m_resourceViewCount = 0;
+ Index m_samplerCount = 0;
+ Index m_combinedTextureSamplerCount = 0;
+ Index m_subObjectCount = 0;
+ Index m_varyingInputCount = 0;
+ Index m_varyingOutputCount = 0;
+
+ struct DescriptorSetBuildInfo : public RefObject
+ {
+ List<DescriptorSetLayout::SlotRangeDesc> slotRangeDescs;
+ Index space;
+ };
+ List<RefPtr<DescriptorSetBuildInfo>> m_descriptorSetBuildInfos;
+ Dictionary<Index, Index> m_mapSpaceToDescriptorSetIndex;
+
+ Index findOrAddDescriptorSet(Index space)
+ {
+ Index index;
+ if(m_mapSpaceToDescriptorSetIndex.TryGetValue(space, index))
+ return index;
+
+ RefPtr<DescriptorSetBuildInfo> info = new DescriptorSetBuildInfo();
+ info->space = space;
+
+ index = m_descriptorSetBuildInfos.getCount();
+ m_descriptorSetBuildInfos.add(info);
+
+ m_mapSpaceToDescriptorSetIndex.Add(space, index);
+ return index;
+ }
+
+ static DescriptorSlotType _mapDescriptorType(slang::BindingType slangBindingType)
+ {
+ switch(slangBindingType)
+ {
+ default: return DescriptorSlotType::Unknown;
+
+ #define CASE(FROM, TO) \
+ case slang::BindingType::FROM: return DescriptorSlotType::TO
+
+ CASE(Sampler, Sampler);
+ CASE(CombinedTextureSampler, CombinedImageSampler);
+ CASE(Texture, SampledImage);
+ CASE(MutableTexture, StorageImage);
+ CASE(TypedBuffer, UniformTexelBuffer);
+ CASE(MutableTypedBuffer, StorageTexelBuffer);
+ CASE(RawBuffer, UniformBuffer);
+ CASE(MutableRawBuffer, StorageBuffer);
+ CASE(InputRenderTarget, InputAttachment);
+ CASE(InlineUniformData, InlineUniformBlock);
+ CASE(RayTracingAccelerationStructure, RayTracingAccelerationStructure);
+ CASE(ConstantBuffer, UniformBuffer);
+ CASE(PushConstant, RootConstant);
+
+ #undef CASE
+ }
+ }
+
+ slang::TypeLayoutReflection* unwrapParameterGroups(slang::TypeLayoutReflection* typeLayout)
+ {
+ for(;;)
+ {
+ if(!typeLayout->getType())
+ {
+ if(auto elementTypeLayout = typeLayout->getElementTypeLayout())
+ typeLayout = elementTypeLayout;
+ }
+
+ switch(typeLayout->getKind())
+ {
+ default:
+ return typeLayout;
+
+ case slang::TypeReflection::Kind::ConstantBuffer:
+ case slang::TypeReflection::Kind::ParameterBlock:
+ typeLayout = typeLayout->getElementTypeLayout();
+ continue;
+ }
+ }
+ }
+
+ void _addDescriptorSets(slang::TypeLayoutReflection* typeLayout, slang::VariableLayoutReflection* varLayout = nullptr)
+ {
+ SlangInt descriptorSetCount = typeLayout->getDescriptorSetCount();
+ for(SlangInt s = 0; s < descriptorSetCount; ++s)
+ {
+ auto descriptorSetIndex = findOrAddDescriptorSet(typeLayout->getDescriptorSetSpaceOffset(s));
+ auto descriptorSetInfo = m_descriptorSetBuildInfos[descriptorSetIndex];
+
+ SlangInt descriptorRangeCount = typeLayout->getDescriptorSetDescriptorRangeCount(s);
+ for(SlangInt r = 0; r < descriptorRangeCount; ++r)
+ {
+ auto slangBindingType = typeLayout->getDescriptorSetDescriptorRangeType(s, r);
+ auto gfxDescriptorType = _mapDescriptorType(slangBindingType);
+
+ DescriptorSetLayout::SlotRangeDesc descriptorRangeDesc;
+ descriptorRangeDesc.binding = typeLayout->getDescriptorSetDescriptorRangeIndexOffset(s, r);
+ descriptorRangeDesc.count = typeLayout->getDescriptorSetDescriptorRangeDescriptorCount(s, r);
+ descriptorRangeDesc.type = gfxDescriptorType;
+
+ if(varLayout)
+ {
+ auto category = typeLayout->getDescriptorSetDescriptorRangeCategory(s, r);
+ descriptorRangeDesc.binding += varLayout->getOffset(category);
+ }
+
+ descriptorSetInfo->slotRangeDescs.add(descriptorRangeDesc);
+ }
+ }
+ }
+
+ Result setElementTypeLayout(slang::TypeLayoutReflection* typeLayout)
+ {
+ typeLayout = unwrapParameterGroups(typeLayout);
+
+ m_elementTypeLayout = typeLayout;
+
+ // First we will use the Slang layout information to allocate
+ // the descriptor set layout(s) required to store values
+ // of the given type.
+ //
+ _addDescriptorSets(typeLayout);
+
+ // Next we will compute the binding ranges that are used to store
+ // the logical contents of the object in memory. These will relate
+ // to the descriptor ranges in the various sets, but not always
+ // in a one-to-one fashion.
+
+ SlangInt bindingRangeCount = typeLayout->getBindingRangeCount();
+ for(SlangInt r = 0; r < bindingRangeCount; ++r)
+ {
+ slang::BindingType slangBindingType = typeLayout->getBindingRangeType(r);
+ SlangInt count = typeLayout->getBindingRangeBindingCount(r);
+ slang::TypeLayoutReflection* slangLeafTypeLayout = typeLayout->getBindingRangeLeafTypeLayout(r);
+
+ SlangInt descriptorSetIndex = typeLayout->getBindingRangeDescriptorSetIndex(r);
+ SlangInt rangeIndexInDescriptorSet = typeLayout->getBindingRangeFirstDescriptorRangeIndex(r);
+
+ Index baseIndex = 0;
+ switch(slangBindingType)
+ {
+ case slang::BindingType::ConstantBuffer:
+ case slang::BindingType::ParameterBlock:
+ case slang::BindingType::ExistentialValue:
+ baseIndex = m_subObjectCount;
+ m_subObjectCount += count;
+ break;
+
+ case slang::BindingType::Sampler:
+ baseIndex = m_samplerCount;
+ m_samplerCount += count;
+ break;
+
+ case slang::BindingType::CombinedTextureSampler:
+ baseIndex = m_combinedTextureSamplerCount;
+ m_combinedTextureSamplerCount += count;
+ break;
+
+ case slang::BindingType::VaryingInput:
+ baseIndex = m_varyingInputCount;
+ m_varyingInputCount += count;
+ break;
+
+ case slang::BindingType::VaryingOutput:
+ baseIndex = m_varyingOutputCount;
+ m_varyingOutputCount += count;
+ break;
+
+ default:
+ baseIndex = m_resourceViewCount;
+ m_resourceViewCount += count;
+ break;
+ }
+
+ BindingRangeInfo bindingRangeInfo;
+ bindingRangeInfo.bindingType = slangBindingType;
+ bindingRangeInfo.count = count;
+// bindingRangeInfo.descriptorSetIndex = descriptorSetIndex;
+// bindingRangeInfo.rangeIndexInDescriptorSet = slotRangeIndex;
+// bindingRangeInfo.subObjectRangeIndex = subObjectRangeIndex;
+ bindingRangeInfo.baseIndex = baseIndex;
+ bindingRangeInfo.descriptorSetIndex = descriptorSetIndex;
+ bindingRangeInfo.rangeIndexInDescriptorSet = rangeIndexInDescriptorSet;
+
+ m_bindingRanges.add(bindingRangeInfo);
+
+#if 0
+ SlangInt binding = typeLayout->getBindingRangeIndexOffset(r);
+ SlangInt space = typeLayout->getBindingRangeSpaceOffset(r);
+ SlangInt subObjectRangeIndex = typeLayout->getBindingRangeSubObjectRangeIndex(r);
+
+ DescriptorSetLayout::SlotRangeDesc slotRange;
+ slotRange.type = _mapDescriptorType(slangBindingType);
+ slotRange.count = count;
+ slotRange.binding = binding;
+
+ Index descriptorSetIndex = findOrAddDescriptorSet(space);
+ RefPtr<DescriptorSetBuildInfo> descriptorSetInfo = m_descriptorSetInfos[descriptorSetIndex];
+
+ Index slotRangeIndex = descriptorSetInfo->slotRanges.getCount();
+ descriptorSetInfo->slotRanges.add(slotRange);
+#endif
+ }
+
+ SlangInt subObjectRangeCount = typeLayout->getSubObjectRangeCount();
+ for(SlangInt r = 0; r < subObjectRangeCount; ++r)
+ {
+ SlangInt bindingRangeIndex = typeLayout->getSubObjectRangeBindingRangeIndex(r);
+ auto slangBindingType = typeLayout->getBindingRangeType(bindingRangeIndex);
+ slang::TypeLayoutReflection* slangLeafTypeLayout = typeLayout->getBindingRangeLeafTypeLayout(bindingRangeIndex);
+
+ // A sub-object range can either represent a sub-object of a known
+ // type, like a `ConstantBuffer<Foo>` or `ParameterBlock<Foo>`
+ // (in which case we can pre-compute a layout to use, based on
+ // the type `Foo`) *or* it can represent a sub-object of some
+ // existential type (e.g., `IBar`) in which case we cannot
+ // know the appropraite type/layout of sub-object to allocate.
+ //
+ RefPtr<ShaderObjectLayout> subObjectLayout;
+ if(slangBindingType != slang::BindingType::ExistentialValue)
+ {
+ ShaderObjectLayout::createForElementType(m_renderer, slangLeafTypeLayout->getElementTypeLayout(), subObjectLayout.writeRef());
+ }
+
+ SubObjectRangeInfo subObjectRange;
+ subObjectRange.bindingRangeIndex = bindingRangeIndex;
+ subObjectRange.layout = subObjectLayout;
+
+ m_subObjectRanges.add(subObjectRange);
+ }
+
+#if 0
+ SlangInt subObjectRangeCount = typeLayout->getSubObjectRangeCount();
+ for(SlangInt r = 0; r < subObjectRangeCount; ++r)
+ {
+
+ // TODO: Still need a way to map the binding ranges for
+ // the sub-object over so that they can be used to
+ // set/get the sub-object as needed.
+ }
+#endif
+ return SLANG_OK;
+ }
+
+ SlangResult build(ShaderObjectLayout** outLayout)
+ {
+ RefPtr<ShaderObjectLayout> layout = new ShaderObjectLayout();
+ SLANG_RETURN_ON_FAIL(layout->_init(this));
+
+ *outLayout = layout.detach();
+ return SLANG_OK;
+ }
+
+ Renderer* m_renderer = nullptr;
+ slang::TypeLayoutReflection* m_elementTypeLayout = nullptr;
+ };
+
+ static Result createForElementType(Renderer* renderer, slang::TypeLayoutReflection* elementType, ShaderObjectLayout** outLayout)
+ {
+ Builder builder(renderer);
+ builder.setElementTypeLayout(elementType);
+ return builder.build(outLayout);
+ }
+
+ List<RefPtr<DescriptorSetInfo>> const& getDescriptorSets() { return m_descriptorSets; }
+
+ List<BindingRangeInfo> const& getBindingRanges() { return m_bindingRanges; }
+
+ Index getBindingRangeCount() { return m_bindingRanges.getCount(); }
+
+ BindingRangeInfo const& getBindingRange(Index index) { return m_bindingRanges[index]; }
+
+ slang::TypeLayoutReflection* getElementTypeLayout()
+ {
+ return m_elementTypeLayout;
+ }
+
+ Index getResourceViewCount() { return m_resourceViewCount; }
+ Index getSamplerCount() { return m_samplerCount; }
+ Index getCombinedTextureSamplerCount() { return m_combinedTextureSamplerCount; }
+ Index getSubObjectCount() { return m_subObjectCount; }
+
+ SubObjectRangeInfo const& getSubObjectRange(Index index) { return m_subObjectRanges[index]; }
+ List<SubObjectRangeInfo> const& getSubObjectRanges() { return m_subObjectRanges; }
+
+ Renderer* getRenderer()
+ {
+ return m_renderer;
+ }
+
+protected:
+ Result _init(Builder const* builder)
+ {
+ auto renderer = builder->m_renderer;
+ m_renderer = renderer;
+
+ m_elementTypeLayout = builder->m_elementTypeLayout;
+ m_bindingRanges = builder->m_bindingRanges;
+
+ for(auto descriptorSetBuildInfo : builder->m_descriptorSetBuildInfos)
+ {
+ auto& slotRangeDescs = descriptorSetBuildInfo->slotRangeDescs;
+ DescriptorSetLayout::Desc desc;
+ desc.slotRangeCount = slotRangeDescs.getCount();
+ desc.slotRanges = slotRangeDescs.getBuffer();
+
+ RefPtr<DescriptorSetLayout> descriptorSetLayout;
+ SLANG_RETURN_ON_FAIL(m_renderer->createDescriptorSetLayout(desc, descriptorSetLayout.writeRef()));
+
+ RefPtr<DescriptorSetInfo> descriptorSetInfo = new DescriptorSetInfo();
+ descriptorSetInfo->layout = descriptorSetLayout;
+ descriptorSetInfo->space = descriptorSetBuildInfo->space;
+
+ m_descriptorSets.add(descriptorSetInfo);
+ }
+
+ m_resourceViewCount = builder->m_resourceViewCount;
+ m_samplerCount = builder->m_samplerCount;
+ m_combinedTextureSamplerCount = builder->m_combinedTextureSamplerCount;
+ m_subObjectCount = builder->m_subObjectCount;
+
+ m_subObjectRanges = builder->m_subObjectRanges;
+
+ return SLANG_OK;
+ }
+
+ Renderer* m_renderer;
+ List<RefPtr<DescriptorSetInfo>> m_descriptorSets;
+ List<BindingRangeInfo> m_bindingRanges;
+ slang::TypeLayoutReflection* m_elementTypeLayout;
+ Index m_resourceViewCount = 0;
+ Index m_samplerCount = 0;
+ Index m_combinedTextureSamplerCount = 0;
+ Index m_subObjectCount = 0;
+ List<SubObjectRangeInfo> m_subObjectRanges;
+};
+
+class EntryPointLayout : public ShaderObjectLayout
+{
+ typedef ShaderObjectLayout Super;
+public:
+
+ struct VaryingInputInfo
+ {
+ };
+
+ struct VaryingOutputInfo
+ {
+ };
+
+ struct Builder : Super::Builder
+ {
+ Builder(Renderer* renderer)
+ : Super::Builder(renderer)
+ {}
+
+ Result build(EntryPointLayout** outLayout)
+ {
+ RefPtr<EntryPointLayout> layout = new EntryPointLayout();
+ SLANG_RETURN_ON_FAIL(layout->_init(this));
+
+ *outLayout = layout.detach();
+ return SLANG_OK;
+ }
+
+ void _addEntryPointParam(slang::VariableLayoutReflection* entryPointParam)
+ {
+ auto slangStage = entryPointParam->getStage();
+ auto typeLayout = entryPointParam->getTypeLayout();
+
+ SlangInt bindingRangeCount = typeLayout->getBindingRangeCount();
+ for(SlangInt r = 0; r < bindingRangeCount; ++r)
+ {
+ slang::BindingType slangBindingType = typeLayout->getBindingRangeType(r);
+ SlangInt count = typeLayout->getBindingRangeBindingCount(r);
+
+ switch(slangBindingType)
+ {
+ default:
+ break;
+
+ case slang::BindingType::VaryingInput:
+ {
+ VaryingInputInfo info;
+
+ m_varyingInputs.add(info);
+ }
+ break;
+
+ case slang::BindingType::VaryingOutput:
+ {
+ VaryingOutputInfo info;
+ m_varyingOutputs.add(info);
+ }
+ break;
+ }
+ }
+ }
+
+ void addEntryPointParams(slang::EntryPointLayout* entryPointLayout)
+ {
+ m_slangEntryPointLayout = entryPointLayout;
+
+ setElementTypeLayout(entryPointLayout->getTypeLayout());
+
+ m_stage = translateStage(entryPointLayout->getStage());
+ _addEntryPointParam(entryPointLayout->getVarLayout());
+ _addEntryPointParam(entryPointLayout->getResultVarLayout());
+ }
+
+ slang::EntryPointLayout* m_slangEntryPointLayout = nullptr;
+
+ gfx::StageType m_stage;
+ List<VaryingInputInfo> m_varyingInputs;
+ List<VaryingOutputInfo> m_varyingOutputs;
+ };
+
+ Result _init(Builder const* builder)
+ {
+ auto renderer = builder->m_renderer;
+
+ SLANG_RETURN_ON_FAIL(Super::_init(builder));
+
+ m_slangEntryPointLayout = builder->m_slangEntryPointLayout;
+ m_stage = builder->m_stage;
+ m_varyingInputs = builder->m_varyingInputs;
+ m_varyingOutputs = builder->m_varyingOutputs;
+
+ return SLANG_OK;
+ }
+
+ List<VaryingInputInfo> const& getVaryingInputs() { return m_varyingInputs; }
+ List<VaryingOutputInfo> const& getVaryingOutputs() { return m_varyingOutputs; }
+
+ gfx::StageType getStage() const { return m_stage; }
+
+ slang::EntryPointLayout* getSlangLayout() const { return m_slangEntryPointLayout; };
+
+ slang::EntryPointLayout* m_slangEntryPointLayout;
+ gfx::StageType m_stage;
+ List<VaryingInputInfo> m_varyingInputs;
+ List<VaryingOutputInfo> m_varyingOutputs;
+};
+
+class ProgramLayout : public ShaderObjectLayout
+{
+ typedef ShaderObjectLayout Super;
+public:
+
+ struct EntryPointInfo
+ {
+ RefPtr<EntryPointLayout> layout;
+ Index rangeOffset;
+ };
+
+
+ struct Builder : Super::Builder
+ {
+ Builder(Renderer* renderer)
+ : Super::Builder(renderer)
+ {}
+
+ Result build(ProgramLayout** outLayout)
+ {
+ RefPtr<ProgramLayout> layout = new ProgramLayout();
+ SLANG_RETURN_ON_FAIL(layout->_init(this));
+
+ *outLayout = layout.detach();
+ return SLANG_OK;
+ }
+
+ void addGlobalParams(slang::VariableLayoutReflection* globalsLayout)
+ {
+ setElementTypeLayout(globalsLayout->getTypeLayout());
+ }
+
+ void addEntryPoint(EntryPointLayout* entryPointLayout)
+ {
+ EntryPointInfo info;
+ info.layout = entryPointLayout;
+
+ if(m_descriptorSetBuildInfos.getCount())
+ {
+ info.rangeOffset = m_descriptorSetBuildInfos[0]->slotRangeDescs.getCount();
+ }
+
+ auto slangEntryPointLayout = entryPointLayout->getSlangLayout();
+ _addDescriptorSets(slangEntryPointLayout->getTypeLayout(), slangEntryPointLayout->getVarLayout());
+
+ m_entryPoints.add(info);
+ }
+
+ List<EntryPointInfo> m_entryPoints;
+ };
+
+ Slang::Int getRenderTargetCount()
+ {
+ return m_renderTargetCount;
+ }
+
+ PipelineLayout* getPipelineLayout() { return m_pipelineLayout; }
+
+ Index findEntryPointIndex(gfx::StageType stage)
+ {
+ auto entryPointCount = m_entryPoints.getCount();
+ for(Index i = 0; i < entryPointCount; ++i)
+ {
+ auto entryPoint = m_entryPoints[i];
+ if(entryPoint.layout->getStage() == stage)
+ return i;
+ }
+ return -1;
+ }
+
+ EntryPointInfo const& getEntryPoint(Index index)
+ {
+ return m_entryPoints[index];
+ }
+
+ List<EntryPointInfo> const& getEntryPoints() const { return m_entryPoints; }
+
+protected:
+ Result _init(Builder const* builder)
+ {
+ auto renderer = builder->m_renderer;
+
+ SLANG_RETURN_ON_FAIL(Super::_init(builder));
+
+ m_entryPoints = builder->m_entryPoints;
+
+ List<PipelineLayout::DescriptorSetDesc> pipelineDescriptorSets;
+ _addDescriptorSetsRec(this, pipelineDescriptorSets);
+
+#if 0
+ _createInputLayout(builder);
+#endif
+
+ auto fragmentEntryPointIndex = findEntryPointIndex(gfx::StageType::Fragment);
+ if(fragmentEntryPointIndex != -1)
+ {
+ auto fragmentEntryPoint = getEntryPoint(fragmentEntryPointIndex);
+ m_renderTargetCount = fragmentEntryPoint.layout->getVaryingOutputs().getCount();
+ }
+
+ PipelineLayout::Desc pipelineLayoutDesc;
+ pipelineLayoutDesc.renderTargetCount = m_renderTargetCount;
+ pipelineLayoutDesc.descriptorSetCount = pipelineDescriptorSets.getCount();
+ pipelineLayoutDesc.descriptorSets = pipelineDescriptorSets.getBuffer();
+
+ SLANG_RETURN_ON_FAIL(renderer->createPipelineLayout(pipelineLayoutDesc, m_pipelineLayout.writeRef()));
+
+ return SLANG_OK;
+ }
+
+ static void _addDescriptorSetsRec(ShaderObjectLayout* layout, List<PipelineLayout::DescriptorSetDesc>& ioPipelineDescriptorSets)
+ {
+ for(auto descriptorSetInfo : layout->getDescriptorSets())
+ {
+ PipelineLayout::DescriptorSetDesc pipelineDescriptorSet;
+ pipelineDescriptorSet.layout = descriptorSetInfo->layout;
+ pipelineDescriptorSet.space = descriptorSetInfo->space;
+
+ ioPipelineDescriptorSets.add(pipelineDescriptorSet);
+ }
+
+ // TODO: next we need to recurse into the "sub-objects" of `layout` and
+ // add their descriptor sets as well.
+ }
+
+#if 0
+ Result _createInputLayout(Builder const* builder)
+ {
+ auto renderer = builder->m_renderer;
+
+ List<InputElementDesc> const& inputElements = builder->getInputElements();
+ SLANG_RETURN_ON_FAIL(renderer->createInputLayout(inputElements.getBuffer(), inputElements.getCount(), m_inputLayout.writeRef()));
+
+ return SLANG_OK;
+ }
+#endif
+
+ List<EntryPointInfo> m_entryPoints;
+ gfx::UInt m_renderTargetCount = 0;
+
+ RefPtr<PipelineLayout> m_pipelineLayout;
+};
+
+class ShaderObject : public RefObject
+{
+public:
+ static Result create(Renderer* renderer, ShaderObjectLayout* layout, ShaderObject** outShaderObject)
+ {
+ RefPtr<ShaderObject> object = new ShaderObject();
+ SLANG_RETURN_ON_FAIL(object->init(renderer, layout));
+
+ *outShaderObject = object.detach();
+ return SLANG_OK;
+ }
+
+ Renderer* getRenderer()
+ {
+ return m_layout->getRenderer();
+ }
+
+ ShaderObjectLayout* getLayout()
+ {
+ return m_layout;
+ }
+
+ slang::TypeLayoutReflection* getElementTypeLayout()
+ {
+ return m_layout->getElementTypeLayout();
+ }
+
+ SlangResult setData(ShaderOffset const& offset, void const* data, size_t size)
+ {
+ Renderer* renderer = getRenderer();
+
+ char* dest = (char*) renderer->map(m_buffer, MapFlavor::HostWrite);
+ memcpy(dest + offset.uniformOffset, data, size);
+ renderer->unmap(m_buffer);
+
+ return SLANG_OK;
+ }
+
+ SlangResult setObject(ShaderOffset const& offset, ShaderObject* object)
+ {
+ if(offset.bindingRangeIndex < 0) return SLANG_E_INVALID_ARG;
+ if(offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) return SLANG_E_INVALID_ARG;
+ auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex);
+
+ // TODO: Is this reasonable to store the base index directly in the binding range?
+ m_objects[bindingRange.baseIndex + offset.bindingArrayIndex] = object;
+
+// auto& subObjectRange = m_layout->getSubObjectRange(bindingRange.subObjectRangeIndex);
+// m_objects[subObjectRange.baseIndex + offset.bindingArrayIndex] = object;
+
+#if 0
+
+ SLANG_ASSERT(bindingRange.descriptorSetIndex >= 0);
+ SLANG_ASSERT(bindingRange.descriptorSetIndex < m_descriptorSets.getCount());
+ auto& descriptorSet = m_descriptorSets[bindingRange.descriptorSetIndex];
+
+ descriptorSet->setConstantBuffer(bindingRange.rangeIndexInDescriptorSet, offset.bindingArrayIndex, buffer);
+ return SLANG_OK;
+#else
+ return SLANG_E_NOT_IMPLEMENTED;
+#endif
+ }
+
+ SlangResult getObject(ShaderOffset const& offset, ShaderObject** outObject)
+ {
+ SLANG_ASSERT(outObject);
+ if(offset.bindingRangeIndex < 0) return SLANG_E_INVALID_ARG;
+ if(offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) return SLANG_E_INVALID_ARG;
+ auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex);
+
+ *outObject = m_objects[bindingRange.baseIndex + offset.bindingArrayIndex];
+
+// auto& subObjectRange = m_layout->getSubObjectRange(bindingRange.subObjectRangeIndex);
+// *outObject = m_objects[subObjectRange.baseIndex + offset.bindingArrayIndex];
+
+ return SLANG_OK;
+
+#if 0
+ SLANG_ASSERT(bindingRange.descriptorSetIndex >= 0);
+ SLANG_ASSERT(bindingRange.descriptorSetIndex < m_descriptorSets.getCount());
+ auto& descriptorSet = m_descriptorSets[bindingRange.descriptorSetIndex];
+
+ descriptorSet->setConstantBuffer(bindingRange.rangeIndexInDescriptorSet, offset.bindingArrayIndex, buffer);
+ return SLANG_OK;
+#endif
+ }
+
+ ShaderObject* getObject(ShaderOffset const& offset)
+ {
+ ShaderObject* object = nullptr;
+ SLANG_RETURN_NULL_ON_FAIL(getObject(offset, &object));
+ return object;
+ }
+
+ SlangResult setResource(ShaderOffset const& offset, ResourceView* resourceView)
+ {
+ if(offset.bindingRangeIndex < 0) return SLANG_E_INVALID_ARG;
+ if(offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) return SLANG_E_INVALID_ARG;
+ auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex);
+
+ m_resourceViews[bindingRange.baseIndex + offset.bindingArrayIndex] = resourceView;
+ return SLANG_OK;
+ }
+
+ SlangResult setSampler(ShaderOffset const& offset, SamplerState* sampler)
+ {
+ if(offset.bindingRangeIndex < 0) return SLANG_E_INVALID_ARG;
+ if(offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) return SLANG_E_INVALID_ARG;
+ auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex);
+
+ m_samplers[bindingRange.baseIndex + offset.bindingArrayIndex] = sampler;
+ return SLANG_OK;
+ }
+
+ SlangResult setCombinedTextureSampler(ShaderOffset const& offset, ResourceView* textureView, SamplerState* sampler)
+ {
+ if(offset.bindingRangeIndex < 0) return SLANG_E_INVALID_ARG;
+ if(offset.bindingRangeIndex >= m_layout->getBindingRangeCount()) return SLANG_E_INVALID_ARG;
+ auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex);
+
+ auto& slot = m_combinedTextureSamplers[bindingRange.baseIndex + offset.bindingArrayIndex];
+ slot.textureView = textureView;
+ slot.sampler = sampler;
+ return SLANG_OK;
+ }
+
+protected:
+ friend class ProgramVars;
+
+ Result init(Renderer* renderer, ShaderObjectLayout* layout)
+ {
+ m_layout = layout;
+
+ // If the layout tells us that there is any uniform data,
+ // then we need to allocate a constant buffer to hold that data.
+ //
+ // TODO: Do we need to allocate a shadow copy for use from
+ // the CPU?
+ //
+ // TODO: When/where do we bind this constant buffer into
+ // a descriptor set for later use?
+ //
+ size_t uniformSize = layout->getElementTypeLayout()->getSize();
+ if(uniformSize)
+ {
+ BufferResource::Desc bufferDesc;
+ bufferDesc.init(uniformSize);
+ bufferDesc.cpuAccessFlags |= Resource::AccessFlag::Write;
+ SLANG_RETURN_ON_FAIL(renderer->createBufferResource(Resource::Usage::ConstantBuffer, bufferDesc, nullptr, m_buffer.writeRef()));
+ }
+
+#if 0
+ // If the layout tells us there are any descriptor sets to
+ // allocate, then we do so now.
+ //
+ for(auto descriptorSetInfo : layout->getDescriptorSets())
+ {
+ RefPtr<DescriptorSet> descriptorSet;
+ SLANG_RETURN_ON_FAIL(renderer->createDescriptorSet(descriptorSetInfo->layout, descriptorSet.writeRef()));
+ m_descriptorSets.add(descriptorSet);
+ }
+#endif
+
+ m_resourceViews.setCount(layout->getResourceViewCount());
+ m_samplers.setCount(layout->getSamplerCount());
+ m_combinedTextureSamplers.setCount(layout->getCombinedTextureSamplerCount());
+
+ // If the layout specifies that we have any sub-objects, then
+ // we need to size the array to account for them.
+ //
+ Index subObjectCount = layout->getSubObjectCount();
+ m_objects.setCount(subObjectCount);
+
+ for(auto subObjectRangeInfo : layout->getSubObjectRanges())
+ {
+ RefPtr<ShaderObjectLayout> subObjectLayout = subObjectRangeInfo.layout;
+
+ // In the case where the sub-object range represents an
+ // existential-type leaf field (e.g., an `IBar`), we
+ // cannot pre-allocate the objet(s) to go into that
+ // range, since we can't possibly know what to allocate
+ // at this point.
+ //
+ if(!subObjectLayout)
+ continue;
+ //
+ // Otherwise, we will allocate a sub-object to fill
+ // in each entry in this range, based on the layout
+ // information we already have.
+
+ auto& bindingRangeInfo = layout->getBindingRange(subObjectRangeInfo.bindingRangeIndex);
+ for(Index i = 0; i < bindingRangeInfo.count; ++i)
+ {
+ RefPtr<ShaderObject> subObject;
+ SLANG_RETURN_ON_FAIL(ShaderObject::create(renderer, subObjectLayout, subObject.writeRef()));
+ m_objects[bindingRangeInfo.baseIndex + i] = subObject;
+ }
+ }
+
+ return SLANG_OK;
+ }
+
+ Result apply(Renderer* renderer, PipelineType pipelineType, PipelineLayout* pipelineLayout, Index& ioRootIndex)
+ {
+ ShaderObjectLayout* layout = m_layout;
+
+ // Create the descritpor sets required by the layout...
+ //
+ List<RefPtr<DescriptorSet>> descriptorSets;
+ for(auto descriptorSetInfo : layout->getDescriptorSets())
+ {
+ RefPtr<DescriptorSet> descriptorSet;
+ SLANG_RETURN_ON_FAIL(renderer->createDescriptorSet(descriptorSetInfo->layout, descriptorSet.writeRef()));
+ descriptorSets.add(descriptorSet);
+ }
+
+ SLANG_RETURN_ON_FAIL(_bindIntoDescriptorSets(descriptorSets.getBuffer()));
+
+ for(auto descriptorSet : descriptorSets)
+ {
+ renderer->setDescriptorSet(pipelineType, pipelineLayout, ioRootIndex++, descriptorSet);
+ }
+
+ return SLANG_OK;
+ }
+
+ Result _bindIntoDescriptorSet(DescriptorSet* descriptorSet, Index baseRangeIndex, Index subObjectRangeArrayIndex)
+ {
+ ShaderObjectLayout* layout = m_layout;
+
+ if(m_buffer)
+ {
+ descriptorSet->setConstantBuffer(baseRangeIndex, subObjectRangeArrayIndex, m_buffer);
+ baseRangeIndex++;
+ }
+
+ for(auto bindingRangeInfo : layout->getBindingRanges())
+ {
+ switch(bindingRangeInfo.bindingType)
+ {
+ case slang::BindingType::VaryingInput:
+ case slang::BindingType::VaryingOutput:
+ continue;
+
+ default:
+ break;
+ }
+
+ SLANG_ASSERT(bindingRangeInfo.descriptorSetIndex == 0);
+
+ auto count = bindingRangeInfo.count;
+ auto baseIndex = bindingRangeInfo.baseIndex;
+
+ auto descriptorRangeIndex = baseRangeIndex + bindingRangeInfo.rangeIndexInDescriptorSet;
+ auto descriptorArrayBaseIndex = subObjectRangeArrayIndex * count;
+
+ switch(bindingRangeInfo.bindingType)
+ {
+ case slang::BindingType::ConstantBuffer:
+ case slang::BindingType::ParameterBlock:
+ break;
+
+ case slang::BindingType::ExistentialValue:
+ //
+ // TODO: If the existential value is one that "fits" into the storage available,
+ // then we should write its data directly into that area. Otherwise, we need
+ // to bind its content as "pending" data which will come after any other data
+ // beloning to the same set (that is, it's starting descriptorRangeIndex will
+ // need to be one after the number of ranges accounted for in the original type)
+ //
+ break;
+
+ case slang::BindingType::CombinedTextureSampler:
+ for(Index i = 0; i < count; ++i)
+ {
+ auto& slot = m_combinedTextureSamplers[baseIndex + i];
+ descriptorSet->setCombinedTextureSampler(descriptorRangeIndex, descriptorArrayBaseIndex + i, slot.textureView, slot.sampler);
+ }
+ break;
+
+ case slang::BindingType::Sampler:
+ for(Index i = 0; i < count; ++i)
+ {
+ descriptorSet->setSampler(descriptorRangeIndex, descriptorArrayBaseIndex + i, m_samplers[baseIndex + i]);
+ }
+ break;
+
+ default:
+ for(Index i = 0; i < count; ++i)
+ {
+ descriptorSet->setResource(descriptorRangeIndex, descriptorArrayBaseIndex + i, m_resourceViews[baseIndex + i]);
+ }
+ break;
+ }
+ }
+
+ return SLANG_OK;
+ }
+
+ public:
+ virtual Result _bindIntoDescriptorSets(RefPtr<DescriptorSet>* descriptorSets)
+ {
+ ShaderObjectLayout* layout = m_layout;
+
+ if(m_buffer)
+ {
+ // TODO: look up binding infor for default constant buffer...
+ descriptorSets[0]->setConstantBuffer(0, 0, m_buffer);
+ }
+
+ // Fill in the descriptor sets based on binding ranges
+ //
+ for(auto bindingRangeInfo : layout->getBindingRanges())
+ {
+ DescriptorSet* descriptorSet = descriptorSets[bindingRangeInfo.descriptorSetIndex];
+ auto rangeIndex = bindingRangeInfo.rangeIndexInDescriptorSet;
+ auto baseIndex = bindingRangeInfo.baseIndex;
+ auto count = bindingRangeInfo.count;
+ switch(bindingRangeInfo.bindingType)
+ {
+ case slang::BindingType::ConstantBuffer:
+ case slang::BindingType::ParameterBlock:
+ for(Index i = 0; i < count; ++i)
+ {
+ ShaderObject* subObject = m_objects[baseIndex + i];
+
+ subObject->_bindIntoDescriptorSet(descriptorSet, rangeIndex, i);
+ }
+ break;
+
+ case slang::BindingType::CombinedTextureSampler:
+ for(Index i = 0; i < count; ++i)
+ {
+ auto& slot = m_combinedTextureSamplers[baseIndex + i];
+ descriptorSet->setCombinedTextureSampler(rangeIndex, i, slot.textureView, slot.sampler);
+ }
+ break;
+
+ case slang::BindingType::Sampler:
+ for(Index i = 0; i < count; ++i)
+ {
+ descriptorSet->setSampler(rangeIndex, i, m_samplers[baseIndex + i]);
+ }
+ break;
+
+ case slang::BindingType::VaryingInput:
+ case slang::BindingType::VaryingOutput:
+ break;
+
+ case slang::BindingType::ExistentialValue:
+ // Here we are binding as if existential value is the same
+ // as a constant buffer or parameter block, which will lead
+ // to incorrect results...
+ for(Index i = 0; i < count; ++i)
+ {
+ ShaderObject* subObject = m_objects[baseIndex + i];
+
+ subObject->_bindIntoDescriptorSet(descriptorSet, rangeIndex, i);
+ }
+ break;
+
+ default:
+ for(Index i = 0; i < count; ++i)
+ {
+ descriptorSet->setResource(rangeIndex, i, m_resourceViews[baseIndex + i]);
+ }
+ break;
+ }
+ }
+ return SLANG_OK;
+ }
+
+
+ RefPtr<ShaderObjectLayout> m_layout = nullptr;
+ RefPtr<BufferResource> m_buffer;
+
+ List<RefPtr<ResourceView>> m_resourceViews;
+
+ List<RefPtr<SamplerState>> m_samplers;
+
+ struct CombinedTextureSamplerSlot
+ {
+ RefPtr<ResourceView> textureView;
+ RefPtr<SamplerState> sampler;
+ };
+ List<CombinedTextureSamplerSlot> m_combinedTextureSamplers;
+
+// List<RefPtr<DescriptorSet>> m_descriptorSets;
+ List<RefPtr<ShaderObject>> m_objects;
+};
+
+class EntryPointVars : public ShaderObject
+{
+ typedef ShaderObject Super;
+
+public:
+ static Result create(Renderer* renderer, EntryPointLayout* layout, EntryPointVars** outShaderObject)
+ {
+ RefPtr<EntryPointVars> object = new EntryPointVars();
+ SLANG_RETURN_ON_FAIL(object->init(renderer, layout));
+
+ *outShaderObject = object.detach();
+ return SLANG_OK;
+ }
+
+ EntryPointLayout* getLayout()
+ {
+ return static_cast<EntryPointLayout*>(m_layout.Ptr());
+ }
+
+protected:
+ Result init(Renderer* renderer, EntryPointLayout* layout)
+ {
+ SLANG_RETURN_ON_FAIL(Super::init(renderer, layout));
+ return SLANG_OK;
+ }
+};
+
+class ProgramVars : public ShaderObject
+{
+ typedef ShaderObject Super;
+
+public:
+ static Result create(Renderer* renderer, ProgramLayout* layout, ProgramVars** outShaderObject)
+ {
+ RefPtr<ProgramVars> object = new ProgramVars();
+ SLANG_RETURN_ON_FAIL(object->init(renderer, layout));
+
+ *outShaderObject = object.detach();
+ return SLANG_OK;
+ }
+
+ ProgramLayout* getLayout()
+ {
+ return static_cast<ProgramLayout*>(m_layout.Ptr());
+ }
+
+ void apply(Renderer* renderer, PipelineType pipelineType)
+ {
+ auto pipelineLayout = getLayout()->getPipelineLayout();
+
+ Index rootIndex = 0;
+ ShaderObject::apply(renderer, pipelineType, pipelineLayout, rootIndex);
+
+#if 0
+
+ Index descriptorSetCount = m_descriptorSets.getCount();
+ for(Index descriptorSetIndex = 0; descriptorSetIndex < descriptorSetCount; ++descriptorSetIndex)
+ {
+ renderer->setDescriptorSet(
+ pipelineType,
+ pipelineLayout,
+ descriptorSetIndex,
+ m_descriptorSets[descriptorSetIndex]);
+ }
+#endif
+
+ // TODO: We also need to bind any descriptor sets that are
+ // part of sub-objects of this object.
+ }
+
+ List<RefPtr<EntryPointVars>> const& getEntryPoints() const { return m_entryPoints; }
+
+protected:
+
+ virtual Result _bindIntoDescriptorSets(RefPtr<DescriptorSet>* descriptorSets)
+ {
+ SLANG_RETURN_ON_FAIL(Super::_bindIntoDescriptorSets(descriptorSets));
+
+ auto entryPointCount = m_entryPoints.getCount();
+ for( Index i = 0; i < entryPointCount; ++i )
+ {
+ auto entryPoint = m_entryPoints[i];
+ auto& entryPointInfo = getLayout()->getEntryPoint(i);
+
+ SLANG_RETURN_ON_FAIL(entryPoint->_bindIntoDescriptorSet(descriptorSets[0], entryPointInfo.rangeOffset, 0));
+ }
+
+ return SLANG_OK;
+ }
+
+
+ Result init(Renderer* renderer, ProgramLayout* layout)
+ {
+ SLANG_RETURN_ON_FAIL(Super::init(renderer, layout));
+
+ for(auto entryPointInfo : layout->getEntryPoints())
+ {
+ RefPtr<EntryPointVars> entryPoint;
+ SLANG_RETURN_ON_FAIL(EntryPointVars::create(renderer, entryPointInfo.layout, entryPoint.writeRef()));
+ m_entryPoints.add(entryPoint);
+ }
+
+ return SLANG_OK;
+ }
+
+ List<RefPtr<EntryPointVars>> m_entryPoints;
+};
+
+ /// Represents a "pointer" to the storage for a shader parameter of a (dynamically) known type.
+ ///
+ /// A `ShaderCursor` serves as a pointer-like type for things stored inside a `ShaderObject`.
+ ///
+ /// A cursor that points to the entire content of a shader object can be formed as `ShaderCursor(someObject)`.
+ /// A cursor pointing to a structure field or array element can be formed from another cursor
+ /// using `getField` or `getElement` respectively.
+ ///
+ /// Given a cursor pointing to a value of some "primitive" type, we can set or get the value
+ /// using operations like `setResource`, `getResource`, etc.
+ ///
+ /// Because type information for shader parameters is being reflected dynamically, all type
+ /// checking for shader cursors occurs at runtime, and errors may occur when attempting to
+ /// set a parameter using a value of an inappropriate type. As much as possible, `ShaderCursor`
+ /// attempts to protect against these cases and return an error `Result` or an invalid
+ /// cursor, rather than allowing operations to proceed with incorrect types.
+ ///
+struct ShaderCursor
+{
+ ShaderObject* m_baseObject = nullptr;
+ slang::TypeLayoutReflection* m_typeLayout = nullptr;
+ ShaderOffset m_offset;
+
+ /// Get the type (layout) of the value being pointed at by the cursor
+ slang::TypeLayoutReflection* getTypeLayout() const
+ {
+ return m_typeLayout;
+ }
+
+ /// Is this cursor valid (that is, does it seem to point to an actual location)?
+ ///
+ /// This check is equivalent to checking whether a pointer is null, so it is
+ /// a very weak sense of "valid." In particular, it is possible to form a
+ /// `ShaderCursor` for which `isValid()` is true, but attempting to get or
+ /// set the value would be an error (like dereferencing a garbage pointer).
+ ///
+ bool isValid() const
+ {
+ return m_baseObject != nullptr;
+ }
+
+ Result getDereferenced(ShaderCursor& outCursor) const
+ {
+ switch(m_typeLayout->getKind())
+ {
+ default:
+ return SLANG_E_INVALID_ARG;
+
+ case slang::TypeReflection::Kind::ConstantBuffer:
+ case slang::TypeReflection::Kind::ParameterBlock:
+ {
+ ShaderObject* subObject = m_baseObject->getObject(m_offset);
+ outCursor = ShaderCursor(subObject);
+ return SLANG_OK;
+ }
+
+ }
+ }
+
+ ShaderCursor getDereferenced()
+ {
+ ShaderCursor result;
+ getDereferenced(result);
+ return result;
+ }
+
+ /// Form a cursor pointing to the field with the given `name` within the value this cursor points at.
+ ///
+ /// If the operation succeeds, then the field cursor is written to `outCursor`.
+ Result getField(UnownedStringSlice const& name, ShaderCursor& outCursor)
+ {
+ // If this cursor is invalid, then can't possible fetch a field.
+ //
+ if(!isValid()) return SLANG_E_INVALID_ARG;
+
+ // If the cursor is valid, we want to consider the type of data
+ // it is referencing.
+ //
+ switch(m_typeLayout->getKind())
+ {
+ // The easy/expected case is when the value has a structure type.
+ //
+ case slang::TypeReflection::Kind::Struct:
+ {
+ // We start by looking up the index of a field matching `name`.
+ //
+ // If there is no such field, we have an error.
+ //
+ SlangInt fieldIndex = m_typeLayout->findFieldIndexByName(name.begin(), name.end());
+ if(fieldIndex == -1)
+ return SLANG_E_INVALID_ARG;
+
+ // Once we know the index of the field being referenced,
+ // we create a cursor to point at the field, based on
+ // the offset information already in this cursor, plus
+ // offsets derived from the field's layout.
+ //
+ slang::VariableLayoutReflection* fieldLayout = m_typeLayout->getFieldByIndex((unsigned int) fieldIndex);
+ ShaderCursor fieldCursor;
+
+ // The field cursorwill point into the same parent object.
+ //
+ fieldCursor.m_baseObject = m_baseObject;
+
+ // The type being pointed to is the tyep of the field.
+ //
+ fieldCursor.m_typeLayout = fieldLayout->getTypeLayout();
+
+ // The byte offset is the current offset plus the relative offset of the field.
+ // The offset in binding ranges is computed similarly.
+ //
+ fieldCursor.m_offset.uniformOffset = m_offset.uniformOffset + fieldLayout->getOffset();
+ fieldCursor.m_offset.bindingRangeIndex = m_offset.bindingRangeIndex + m_typeLayout->getFieldBindingRangeOffset(fieldIndex);
+
+ // The index of the field within any binding ranges will be the same
+ // as the index computed for the parent structure.
+ //
+ // Note: this case would arise for an array of structures with texture-type
+ // fields. Suppose we have:
+ //
+ // struct S { Texture2D t; Texture2D u; }
+ // S g[4];
+ //
+ // In this scenario, `g` holds two binding ranges:
+ //
+ // * Range #0 comprises 4 textures, representing `g[...].t`
+ // * Range #1 comprises 4 textures, representing `g[...].u`
+ //
+ // A cursor for `g[2]` would have a `bindingRangeIndex` of zero but
+ // a `bindingArrayIndex` of 2, iindicating that we could end up
+ // referencing either range, but no matter what we know the index
+ // is 2. Thus when we form a cursor for `g[2].u` we want to
+ // apply the binding range offset to get a `bindingRangeIndex` of
+ // 1, while the `bindingArrayIndex` is unmodified.
+ //
+ // The result is that `g[2].u` is stored in range #1 at array index 2.
+ //
+ fieldCursor.m_offset.bindingArrayIndex = m_offset.bindingArrayIndex;
+
+ outCursor = fieldCursor;
+ return SLANG_OK;
+ }
+ break;
+
+ // In some cases the user might be trying to acess a field by name
+ // from a cursor that references a constant buffer or parameter block,
+ // and in these cases we want the access to Just Work.
+ //
+ case slang::TypeReflection::Kind::ConstantBuffer:
+ case slang::TypeReflection::Kind::ParameterBlock:
+ {
+ // We basically need to "dereference" the current cursor
+ // to go from a pointer to a constant buffer to a pointer
+ // to the *contents* of the constant buffer.
+ //
+ ShaderCursor d = getDereferenced();
+ return d.getField(name, outCursor);
+ }
+ break;
+ }
+
+ return SLANG_E_INVALID_ARG;
+ }
+
+ ShaderCursor getField(UnownedStringSlice const& name)
+ {
+ ShaderCursor cursor;
+ getField(name, cursor);
+ return cursor;
+ }
+
+ ShaderCursor getField(String const& name)
+ {
+ return getField(name.getUnownedSlice());
+ }
+
+ ShaderCursor getElement(Index index)
+ {
+ // TODO: need to auto-dereference various buffer types...
+
+ if(m_typeLayout->getKind() == slang::TypeReflection::Kind::Array)
+ {
+ ShaderCursor elementCursor;
+ elementCursor.m_baseObject = m_baseObject;
+ elementCursor.m_typeLayout = m_typeLayout->getElementTypeLayout();
+ elementCursor.m_offset.uniformOffset = m_offset.uniformOffset + index * m_typeLayout->getElementStride(SLANG_PARAMETER_CATEGORY_UNIFORM);
+ elementCursor.m_offset.bindingRangeIndex = m_offset.bindingRangeIndex;
+ elementCursor.m_offset.bindingArrayIndex = m_offset.bindingArrayIndex*m_typeLayout->getElementCount() + index;
+ return elementCursor;
+ }
+
+ return ShaderCursor();
+ }
+
+ static int _peek(UnownedStringSlice const& slice)
+ {
+ const char* b = slice.begin();
+ const char* e = slice.end();
+ if(b == e) return -1;
+ return *b;
+ }
+
+ static int _get(UnownedStringSlice& slice)
+ {
+ const char* b = slice.begin();
+ const char* e = slice.end();
+ if(b == e) return -1;
+ auto result = *b++;
+ slice = UnownedStringSlice(b, e);
+ return result;
+ }
+
+ static Result followPath(UnownedStringSlice const& path, ShaderCursor& ioCursor)
+ {
+ ShaderCursor cursor = ioCursor;
+
+ enum
+ {
+ ALLOW_NAME = 0x1,
+ ALLOW_SUBSCRIPT = 0x2,
+ ALLOW_DOT = 0x4,
+ };
+ int state = ALLOW_NAME | ALLOW_SUBSCRIPT;
+
+ UnownedStringSlice rest = path;
+ for(;;)
+ {
+ int c = _peek(rest);
+
+ if(c == -1)
+ break;
+ else if( c == '.' )
+ {
+ if(!(state & ALLOW_DOT))
+ return SLANG_E_INVALID_ARG;
+
+ _get(rest);
+ state = ALLOW_NAME;
+ continue;
+ }
+ else if( c == '[' )
+ {
+ if(!(state & ALLOW_SUBSCRIPT))
+ return SLANG_E_INVALID_ARG;
+
+ _get(rest);
+ Index index = 0;
+ while(_peek(rest) != ']')
+ {
+ int d = _get(rest);
+ if(d >= '0' && d <= '9')
+ {
+ index = index*10 + (d - '0');
+ }
+ else
+ {
+ return SLANG_E_INVALID_ARG;
+ }
+ }
+
+ if(_peek(rest) != ']')
+ return SLANG_E_INVALID_ARG;
+ _get(rest);
+
+ cursor = cursor.getElement(index);
+ state = ALLOW_DOT | ALLOW_SUBSCRIPT;
+ continue;
+ }
+ else
+ {
+ const char* nameBegin = rest.begin();
+ for(;;)
+ {
+ switch(_peek(rest))
+ {
+ default:
+ _get(rest);
+ continue;
+
+ case -1:
+ case '.':
+ case '[':
+ break;
+ }
+ break;
+ }
+ char const* nameEnd = rest.begin();
+ UnownedStringSlice name(nameBegin, nameEnd);
+ cursor = cursor.getField(name);
+ state = ALLOW_DOT | ALLOW_SUBSCRIPT;
+ continue;
+ }
+ }
+
+ ioCursor = cursor;
+ return SLANG_OK;
+ }
+
+ static Result followPath(String const& path, ShaderCursor& ioCursor)
+ {
+ return followPath(path.getUnownedSlice(), ioCursor);
+ }
+
+ ShaderCursor getPath(UnownedStringSlice const& path)
+ {
+ ShaderCursor result(*this);
+ followPath(path, result);
+ return result;
+ }
+
+
+ ShaderCursor getPath(String const& path)
+ {
+ ShaderCursor result(*this);
+ followPath(path, result);
+ return result;
+ }
+
+ ShaderCursor()
+ {}
+
+ ShaderCursor(ShaderObject* object)
+ : m_baseObject(object)
+ , m_typeLayout(object->getElementTypeLayout())
+ {}
+
+ SlangResult setData(void const* data, size_t size)
+ {
+ return m_baseObject->setData(m_offset, data, size);
+ }
+
+ SlangResult setObject(ShaderObject* object)
+ {
+ return m_baseObject->setObject(m_offset, object);
+ }
+
+ SlangResult setResource(ResourceView* resourceView)
+ {
+ return m_baseObject->setResource(m_offset, resourceView);
+ }
+
+ SlangResult setSampler(SamplerState* sampler)
+ {
+ return m_baseObject->setSampler(m_offset, sampler);
+ }
+
+ SlangResult setCombinedTextureSampler(ResourceView* textureView, SamplerState* sampler)
+ {
+ return m_baseObject->setCombinedTextureSampler(m_offset, textureView, sampler);
+ }
+};
+
+SlangResult _assignVarsFromLayout(
+ Renderer* renderer,
+ ProgramVars* shaderObject,
+ ShaderInputLayout const& layout,
+ ShaderOutputPlan& ioOutputPlan,
+ slang::ProgramLayout* slangReflection)
+{
+ ShaderCursor rootCursor = ShaderCursor(shaderObject);
+
+ const int textureBindFlags = Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource;
+
+ Index entryCount = layout.entries.getCount();
+ for(Index entryIndex = 0; entryIndex < entryCount; ++entryIndex)
+ {
+ auto& entry = layout.entries[entryIndex];
+ if(entry.name.getLength() == 0)
+ {
+ StdWriters::getError().print("error: entries in `ShaderInputLayout` must include a name\n");
+ return SLANG_E_INVALID_ARG;
+ }
+
+ auto entryCursor = rootCursor.getPath(entry.name);
+
+ if(!entryCursor.isValid())
+ {
+ for(auto entryPoint : shaderObject->getEntryPoints())
+ {
+ entryCursor = ShaderCursor(entryPoint).getPath(entry.name);
+ if(entryCursor.isValid())
+ break;
+ }
+ }
+
+
+ if(!entryCursor.isValid())
+ {
+ StdWriters::getError().print("error: could not find shader parameter matching '%s'\n", entry.name.begin());
+ return SLANG_E_INVALID_ARG;
+ }
+
+ RefPtr<Resource> resource;
+ switch(entry.type)
+ {
+ case ShaderInputType::Uniform:
+ {
+ const size_t bufferSize = entry.bufferData.getCount() * sizeof(uint32_t);
+
+ ShaderCursor dataCursor = entryCursor;
+ switch(dataCursor.getTypeLayout()->getKind())
+ {
+ case slang::TypeReflection::Kind::ConstantBuffer:
+ case slang::TypeReflection::Kind::ParameterBlock:
+ dataCursor = dataCursor.getDereferenced();
+ break;
+
+ default:
+ break;
+
+ }
+
+ dataCursor.setData(entry.bufferData.getBuffer(), bufferSize);
+ }
+ break;
+
+ case ShaderInputType::Buffer:
+ {
+ const InputBufferDesc& srcBuffer = entry.bufferDesc;
+ const size_t bufferSize = entry.bufferData.getCount() * sizeof(uint32_t);
+
+ switch(srcBuffer.type)
+ {
+ case InputBufferType::ConstantBuffer:
+ {
+ // A `cbuffer` input line actually represents the data we
+ // want to write *into* the buffer, and shouldn't
+ // allocate a buffer itself.
+ //
+ entryCursor.getDereferenced().setData(entry.bufferData.getBuffer(), bufferSize);
+ }
+ break;
+
+ case InputBufferType::RootConstantBuffer:
+ {
+ // A `root_constants` input line actually represents the data we
+ // want to write *into* the buffer, and shouldn't
+ // allocate a buffer itself.
+ //
+ // Note: we are not doing `.getDereferenced()` here because the
+ // `root_constant` line should be referring to a parameter value
+ // inside the root-constant range, and not the range/buffer itself.
+ //
+ entryCursor.setData(entry.bufferData.getBuffer(), bufferSize);
+ }
+ break;
+
+ default:
+ {
+
+ RefPtr<BufferResource> bufferResource;
+ SLANG_RETURN_ON_FAIL(ShaderRendererUtil::createBufferResource(entry.bufferDesc, entry.isOutput, bufferSize, entry.bufferData.getBuffer(), renderer, bufferResource));
+ resource = bufferResource;
+
+ ResourceView::Desc viewDesc;
+ viewDesc.type = ResourceView::Type::UnorderedAccess;
+ viewDesc.format = srcBuffer.format;
+ auto bufferView = renderer->createBufferView(
+ bufferResource,
+ viewDesc);
+ entryCursor.setResource(bufferView);
+ }
+ break;
+ }
+
+#if 0
+ switch(srcBuffer.type)
+ {
+ case InputBufferType::ConstantBuffer:
+ descriptorSet->setConstantBuffer(rangeIndex, 0, bufferResource);
+ break;
+
+ case InputBufferType::StorageBuffer:
+ {
+ ResourceView::Desc viewDesc;
+ viewDesc.type = ResourceView::Type::UnorderedAccess;
+ viewDesc.format = srcBuffer.format;
+ auto bufferView = renderer->createBufferView(
+ bufferResource,
+ viewDesc);
+ descriptorSet->setResource(rangeIndex, 0, bufferView);
+ }
+ break;
+ }
+
+ if(srcEntry.isOutput)
+ {
+ BindingStateImpl::OutputBinding binding;
+ binding.entryIndex = i;
+ binding.resource = bufferResource;
+ outputBindings.add(binding);
+ }
+#endif
+ }
+ break;
+
+ case ShaderInputType::CombinedTextureSampler:
+ {
+ RefPtr<TextureResource> texture;
+ SLANG_RETURN_ON_FAIL(ShaderRendererUtil::generateTextureResource(entry.textureDesc, textureBindFlags, renderer, texture));
+ resource = texture;
+
+ auto sampler = _createSamplerState(renderer, entry.samplerDesc);
+
+ ResourceView::Desc viewDesc;
+ viewDesc.type = ResourceView::Type::ShaderResource;
+ auto textureView = renderer->createTextureView(
+ texture,
+ viewDesc);
+
+ entryCursor.setCombinedTextureSampler(textureView, sampler);
+
+#if 0
+ descriptorSet->setCombinedTextureSampler(rangeIndex, 0, textureView, sampler);
+
+ if(srcEntry.isOutput)
+ {
+ BindingStateImpl::OutputBinding binding;
+ binding.entryIndex = i;
+ binding.resource = texture;
+ outputBindings.add(binding);
+ }
+#endif
+ }
+ break;
+
+ case ShaderInputType::Texture:
+ {
+ RefPtr<TextureResource> texture;
+ SLANG_RETURN_ON_FAIL(ShaderRendererUtil::generateTextureResource(entry.textureDesc, textureBindFlags, renderer, texture));
+ resource = texture;
+
+ // TODO: support UAV textures...
+
+ ResourceView::Desc viewDesc;
+ viewDesc.type = ResourceView::Type::ShaderResource;
+ auto textureView = renderer->createTextureView(
+ texture,
+ viewDesc);
+
+ if (!textureView)
+ {
+ return SLANG_FAIL;
+ }
+
+ entryCursor.setResource(textureView);
+
+#if 0
+ descriptorSet->setResource(rangeIndex, 0, textureView);
+
+ if(srcEntry.isOutput)
+ {
+ BindingStateImpl::OutputBinding binding;
+ binding.entryIndex = i;
+ binding.resource = texture;
+ outputBindings.add(binding);
+ }
+#endif
+ }
+ break;
+
+ case ShaderInputType::Sampler:
+ {
+ auto sampler = _createSamplerState(renderer, entry.samplerDesc);
+
+ entryCursor.setSampler(sampler);
+#if 0
+ descriptorSet->setSampler(rangeIndex, 0, sampler);
+#endif
+ }
+ break;
+
+ case ShaderInputType::Object:
+ {
+ auto typeName = entry.objectDesc.typeName;
+ auto slangType = slangReflection->findTypeByName(typeName.getBuffer());
+ auto slangTypeLayout = slangReflection->getTypeLayout(slangType);
+
+ RefPtr<ShaderObjectLayout> shaderObjectLayout;
+ SLANG_RETURN_ON_FAIL(ShaderObjectLayout::createForElementType(renderer, slangTypeLayout, shaderObjectLayout.writeRef()));
+
+ RefPtr<ShaderObject> shaderObject;
+ SLANG_RETURN_ON_FAIL(ShaderObject::create(renderer, shaderObjectLayout, shaderObject.writeRef()));
+
+ entryCursor.setObject(shaderObject);
+ }
+ break;
+
+ default:
+ assert(!"Unhandled type");
+ return SLANG_FAIL;
+ }
+
+ if(entry.isOutput)
+ {
+ ShaderOutputPlan::Item item;
+ item.inputLayoutEntryIndex = entryIndex;
+ item.resource = resource;
+ ioOutputPlan.items.add(item);
+ }
+
+ }
+ return SLANG_OK;
+}
+
+void LegacyRenderTestApp::applyBinding(PipelineType pipelineType)
+{
+ m_bindingState->apply(m_renderer.Ptr(), pipelineType);
+}
+
+void ShaderObjectRenderTestApp::applyBinding(PipelineType pipelineType)
+{
+ m_programVars->apply(m_renderer.Ptr(), pipelineType);
+}
+
+SlangResult LegacyRenderTestApp::initialize(
+ SlangSession* session,
+ Renderer* renderer,
+ const Options& options,
+ const ShaderCompilerUtil::Input& input)
{
m_options = options;
SLANG_RETURN_ON_FAIL(_initializeShaders(session, renderer, options.shaderType, input));
m_numAddedConstantBuffers = 0;
- m_renderer = renderer;
+ m_renderer = renderer;
// TODO(tfoley): use each API's reflection interface to query the constant-buffer size needed
m_constantBufferSize = 16 * sizeof(float);
@@ -129,16 +1934,17 @@ SlangResult RenderTestApp::initialize(SlangSession* session, Renderer* renderer,
constantBufferDesc.init(m_constantBufferSize);
constantBufferDesc.cpuAccessFlags = Resource::AccessFlag::Write;
- m_constantBuffer = renderer->createBufferResource(Resource::Usage::ConstantBuffer, constantBufferDesc);
+ m_constantBuffer =
+ renderer->createBufferResource(Resource::Usage::ConstantBuffer, constantBufferDesc);
if (!m_constantBuffer)
return SLANG_FAIL;
//! Hack -> if doing a graphics test, add an extra binding for our dynamic constant buffer
//
- // TODO: Should probably be more sophisticated than this - with 'dynamic' constant buffer/s binding always being specified
- // in the test file
+ // TODO: Should probably be more sophisticated than this - with 'dynamic' constant buffer/s
+ // binding always being specified in the test file
RefPtr<BufferResource> addedConstantBuffer;
- switch(m_options.shaderType)
+ switch (m_options.shaderType)
{
default:
break;
@@ -151,7 +1957,8 @@ SlangResult RenderTestApp::initialize(SlangSession* session, Renderer* renderer,
}
BindingStateImpl* bindingState = nullptr;
- SLANG_RETURN_ON_FAIL(ShaderRendererUtil::createBindingState(m_shaderInputLayout, m_renderer, addedConstantBuffer, &bindingState));
+ SLANG_RETURN_ON_FAIL(ShaderRendererUtil::createBindingState(
+ m_shaderInputLayout, m_renderer, addedConstantBuffer, &bindingState));
m_bindingState = bindingState;
// Do other initialization that doesn't depend on the source language.
@@ -159,24 +1966,25 @@ SlangResult RenderTestApp::initialize(SlangSession* session, Renderer* renderer,
// Input Assembler (IA)
const InputElementDesc inputElements[] = {
- { "A", 0, Format::RGB_Float32, offsetof(Vertex, position) },
- { "A", 1, Format::RGB_Float32, offsetof(Vertex, color) },
- { "A", 2, Format::RG_Float32, offsetof(Vertex, uv) },
+ {"A", 0, Format::RGB_Float32, offsetof(Vertex, position)},
+ {"A", 1, Format::RGB_Float32, offsetof(Vertex, color)},
+ {"A", 2, Format::RG_Float32, offsetof(Vertex, uv)},
};
m_inputLayout = renderer->createInputLayout(inputElements, SLANG_COUNT_OF(inputElements));
- if(!m_inputLayout)
+ if (!m_inputLayout)
return SLANG_FAIL;
BufferResource::Desc vertexBufferDesc;
vertexBufferDesc.init(kVertexCount * sizeof(Vertex));
- m_vertexBuffer = renderer->createBufferResource(Resource::Usage::VertexBuffer, vertexBufferDesc, kVertexData);
- if(!m_vertexBuffer)
+ m_vertexBuffer = renderer->createBufferResource(
+ Resource::Usage::VertexBuffer, vertexBufferDesc, kVertexData);
+ if (!m_vertexBuffer)
return SLANG_FAIL;
{
- switch(m_options.shaderType)
+ switch (m_options.shaderType)
{
default:
assert(!"unexpected test shader type");
@@ -211,6 +2019,134 @@ SlangResult RenderTestApp::initialize(SlangSession* session, Renderer* renderer,
return m_pipelineState ? SLANG_OK : SLANG_FAIL;
}
+SlangResult ShaderObjectRenderTestApp::initialize(
+ SlangSession* session,
+ Renderer* renderer,
+ const Options& options,
+ const ShaderCompilerUtil::Input& input)
+{
+ m_options = options;
+
+ // We begin by compiling the shader file and entry points that specified via the options.
+ //
+ SLANG_RETURN_ON_FAIL(ShaderCompilerUtil::compileWithLayout(session, options, input, m_compilationOutput));
+ m_shaderInputLayout = m_compilationOutput.layout;
+
+ // Once the shaders have been compiled we load them via the underlying API.
+ //
+ SLANG_RETURN_ON_FAIL(renderer->createProgram(m_compilationOutput.output.desc, m_shaderProgram.writeRef()));
+
+ // If we are doing a non-pass-through compilation, then we will rely on
+ // Slang's reflection API to tell us what the parameters of the program are.
+ //
+ RefPtr<ProgramLayout> programLayout = nullptr;
+
+ // Okay, we will use Slang reflection to determine what the parameters of the shader are.
+ //
+ auto slangReflection = (slang::ProgramLayout*) spGetReflection(m_compilationOutput.output.getRequestForReflection());
+ {
+ ProgramLayout::Builder builder(renderer);
+ builder.addGlobalParams(slangReflection->getGlobalParamsVarLayout());
+
+ // TODO: Also need to reflect entry points here.
+
+ SlangInt entryPointCount = slangReflection->getEntryPointCount();
+ for(SlangInt e = 0; e < entryPointCount; ++e)
+ {
+ auto slangEntryPoint = slangReflection->getEntryPointByIndex(e);
+
+ EntryPointLayout::Builder entryPointBuilder(renderer);
+ entryPointBuilder.addEntryPointParams(slangEntryPoint);
+
+ RefPtr<EntryPointLayout> entryPointLayout;
+ SLANG_RETURN_ON_FAIL(entryPointBuilder.build(entryPointLayout.writeRef()));
+
+ builder.addEntryPoint(entryPointLayout);
+ }
+
+ SLANG_RETURN_ON_FAIL(builder.build(programLayout.writeRef()));
+ }
+
+ // The shape of the parameters will determine the pipeline layout that we use.
+ //
+ RefPtr<PipelineLayout> pipelineLayout = programLayout->getPipelineLayout();
+
+ // Once we have determined the layout of all the parameters we need to bind,
+ // we will create a shader object to use for storing and binding those parameters.
+ //
+ RefPtr<ProgramVars> programVars;
+ SLANG_RETURN_ON_FAIL(ProgramVars::create(renderer, programLayout, programVars.writeRef()));
+ m_programVars = programVars;
+
+ // Now we need to assign from the input parameter data that was parsed into
+ // the program vars we allocated.
+ //
+ SLANG_RETURN_ON_FAIL(_assignVarsFromLayout(renderer, programVars, m_compilationOutput.layout, m_outputPlan, slangReflection));
+
+ m_renderer = renderer;
+
+ // TODO(tfoley): use each API's reflection interface to query the constant-buffer size needed
+// m_constantBufferSize = 16 * sizeof(float);
+
+ {
+ switch(m_options.shaderType)
+ {
+ default:
+ assert(!"unexpected test shader type");
+ return SLANG_FAIL;
+
+ case Options::ShaderProgramType::Compute:
+ {
+ ComputePipelineStateDesc desc;
+ desc.pipelineLayout = pipelineLayout;
+ desc.program = m_shaderProgram;
+
+ m_pipelineState = renderer->createComputePipelineState(desc);
+ }
+ break;
+
+ case Options::ShaderProgramType::Graphics:
+ case Options::ShaderProgramType::GraphicsCompute:
+ {
+ // TODO: We should conceivably be able to match up the "available" vertex
+ // attributes, as defined by the vertex stream(s) on the model being
+ // renderer, with the "required" vertex attributes as defiend on the
+ // shader.
+ //
+ // For now we just create a fixed input layout for all graphics tests
+ // since at present they all draw the same single triangle with a
+ // fixed/known set of attributes.
+ //
+ const InputElementDesc inputElements[] = {
+ { "A", 0, Format::RGB_Float32, offsetof(Vertex, position) },
+ { "A", 1, Format::RGB_Float32, offsetof(Vertex, color) },
+ { "A", 2, Format::RG_Float32, offsetof(Vertex, uv) },
+ };
+
+ RefPtr<InputLayout> inputLayout;
+ SLANG_RETURN_ON_FAIL(renderer->createInputLayout(inputElements, SLANG_COUNT_OF(inputElements), inputLayout.writeRef()));
+
+ BufferResource::Desc vertexBufferDesc;
+ vertexBufferDesc.init(kVertexCount * sizeof(Vertex));
+
+ SLANG_RETURN_ON_FAIL(renderer->createBufferResource(Resource::Usage::VertexBuffer, vertexBufferDesc, kVertexData, m_vertexBuffer.writeRef()));
+
+ GraphicsPipelineStateDesc desc;
+ desc.pipelineLayout = pipelineLayout;
+ desc.program = m_shaderProgram;
+ desc.inputLayout = inputLayout;
+ desc.renderTargetCount = programLayout->getRenderTargetCount();
+
+ m_pipelineState = renderer->createGraphicsPipelineState(desc);
+ }
+ break;
+ }
+ }
+
+ // If success must have a pipeline state
+ return m_pipelineState ? SLANG_OK : SLANG_FAIL;
+}
+
Result RenderTestApp::_initializeShaders(SlangSession* session, Renderer* renderer, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input)
{
SLANG_RETURN_ON_FAIL(ShaderCompilerUtil::compileWithLayout(session, m_options, input, m_compilationOutput));
@@ -219,16 +2155,36 @@ Result RenderTestApp::_initializeShaders(SlangSession* session, Renderer* render
return m_shaderProgram ? SLANG_OK : SLANG_FAIL;
}
-void RenderTestApp::renderFrame()
+
+void LegacyRenderTestApp::setProjectionMatrix()
{
auto mappedData = m_renderer->map(m_constantBuffer, MapFlavor::WriteDiscard);
- if(mappedData)
+ if (mappedData)
{
- const ProjectionStyle projectionStyle = RendererUtil::getProjectionStyle(m_renderer->getRendererType());
+ const ProjectionStyle projectionStyle =
+ RendererUtil::getProjectionStyle(m_renderer->getRendererType());
RendererUtil::getIdentityProjection(projectionStyle, (float*)mappedData);
- m_renderer->unmap(m_constantBuffer);
+ m_renderer->unmap(m_constantBuffer);
}
+}
+
+void ShaderObjectRenderTestApp::setProjectionMatrix()
+{
+ const ProjectionStyle projectionStyle =
+ RendererUtil::getProjectionStyle(m_renderer->getRendererType());
+
+ float projectionMatrix[16];
+ RendererUtil::getIdentityProjection(projectionStyle, projectionMatrix);
+ ShaderCursor(m_programVars)
+ .getField("Uniforms")
+ .getDereferenced()
+ .setData(projectionMatrix, sizeof(projectionMatrix));
+}
+
+void RenderTestApp::renderFrame()
+{
+ setProjectionMatrix();
auto pipelineType = PipelineType::Graphics;
@@ -237,7 +2193,7 @@ void RenderTestApp::renderFrame()
m_renderer->setPrimitiveTopology(PrimitiveTopology::TriangleList);
m_renderer->setVertexBuffer(0, m_vertexBuffer, sizeof(Vertex));
- m_bindingState->apply(m_renderer, pipelineType);
+ applyBinding(pipelineType);
m_renderer->draw(3);
}
@@ -246,7 +2202,7 @@ void RenderTestApp::runCompute()
{
auto pipelineType = PipelineType::Compute;
m_renderer->setPipelineState(pipelineType, m_pipelineState);
- m_bindingState->apply(m_renderer, pipelineType);
+ applyBinding(pipelineType);
m_startTicks = ProcessUtil::getClockTick();
@@ -257,7 +2213,7 @@ void RenderTestApp::finalize()
{
}
-Result RenderTestApp::writeBindingOutput(BindRoot* bindRoot, const char* fileName)
+Result LegacyRenderTestApp::writeBindingOutput(BindRoot* bindRoot, const char* fileName)
{
// Submit the work
m_renderer->submitGpuWork();
@@ -304,6 +2260,51 @@ Result RenderTestApp::writeBindingOutput(BindRoot* bindRoot, const char* fileNam
return SLANG_OK;
}
+Result ShaderObjectRenderTestApp::writeBindingOutput(BindRoot* bindRoot, const char* fileName)
+{
+ // Submit the work
+ m_renderer->submitGpuWork();
+ // Wait until everything is complete
+ m_renderer->waitForGpu();
+
+ FILE * f = fopen(fileName, "wb");
+ if (!f)
+ {
+ return SLANG_FAIL;
+ }
+ FileWriter writer(f, WriterFlags(0));
+
+ for(auto outputItem : m_outputPlan.items)
+ {
+ auto& inputEntry = m_shaderInputLayout.entries[outputItem.inputLayoutEntryIndex];
+ assert(inputEntry.isOutput);
+
+ auto resource = outputItem.resource;
+ if (resource && resource->isBuffer())
+ {
+ BufferResource* bufferResource = static_cast<BufferResource*>(resource.Ptr());
+ const size_t bufferSize = bufferResource->getDesc().sizeInBytes;
+
+ unsigned int* ptr = (unsigned int*)m_renderer->map(bufferResource, MapFlavor::HostRead);
+ if (!ptr)
+ {
+ return SLANG_FAIL;
+ }
+
+ const SlangResult res = ShaderInputLayout::writeBinding(bindRoot, inputEntry, ptr, bufferSize, &writer);
+
+ m_renderer->unmap(bufferResource);
+
+ SLANG_RETURN_ON_FAIL(res);
+ }
+ else
+ {
+ printf("invalid output type at %d.\n", int(outputItem.inputLayoutEntryIndex));
+ }
+ }
+ return SLANG_OK;
+}
+
Result RenderTestApp::writeScreen(const char* filename)
{
@@ -338,6 +2339,7 @@ Result RenderTestApp::update(Window* window)
if (m_options.performanceProfile)
{
+#if 0
// It might not be enough on some APIs to 'waitForGpu' to mean the computation has completed. Let's lock an output
// buffer to be sure
if (m_bindingState->outputBindings.getCount() > 0)
@@ -360,6 +2362,7 @@ Result RenderTestApp::update(Window* window)
m_renderer->unmap(bufferResource);
}
}
+#endif
// Note we don't do the same with screen rendering -> as that will do a lot of work, which may swamp any computation
// so can only really profile compute shaders at the moment
@@ -373,7 +2376,7 @@ Result RenderTestApp::update(Window* window)
{
if (m_options.shaderType == Options::ShaderProgramType::Compute || m_options.shaderType == Options::ShaderProgramType::GraphicsCompute)
{
- auto request = m_compilationOutput.output.request;
+ auto request = m_compilationOutput.output.getRequestForReflection();
auto slangReflection = (slang::ShaderReflection*) spGetReflection(request);
BindSet bindSet;
@@ -629,7 +2632,7 @@ static SlangResult _innerMain(Slang::StdWriters* stdWriters, SlangSession* sessi
{
// Get the shared library -> it contains the executable code, we need to keep around if we recompile
ComPtr<ISlangSharedLibrary> sharedLibrary;
- SLANG_RETURN_ON_FAIL(spGetEntryPointHostCallable(compilationAndLayout.output.request, 0, 0, sharedLibrary.writeRef()));
+ SLANG_RETURN_ON_FAIL(spGetEntryPointHostCallable(compilationAndLayout.output.getRequestForKernels(), 0, 0, sharedLibrary.writeRef()));
// This is a hack to work around, reflection when compiling straight C/C++ code. In that case the code is just passed
// straight through to the C++ compiler so no reflection. In these tests though we should have conditional code
@@ -780,7 +2783,11 @@ static SlangResult _innerMain(Slang::StdWriters* stdWriters, SlangSession* sessi
}
{
- RefPtr<RenderTestApp> app(new RenderTestApp);
+ RefPtr<RenderTestApp> app;
+ if (options.useShaderObjects)
+ app = new ShaderObjectRenderTestApp();
+ else
+ app = new LegacyRenderTestApp();
SLANG_RETURN_ON_FAIL(app->initialize(session, renderer, options, input));
window->show();
return window->runLoop(app);
diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp
index 6c6f67c86..5f43b254d 100644
--- a/tools/render-test/shader-input-layout.cpp
+++ b/tools/render-test/shader-input-layout.cpp
@@ -140,11 +140,19 @@ namespace renderer_test
entry.type = ShaderInputType::Buffer;
entry.bufferDesc.type = InputBufferType::ConstantBuffer;
}
+ else if (parser.LookAhead("object"))
+ {
+ entry.type = ShaderInputType::Object;
+ }
else if (parser.LookAhead("root_constants"))
{
entry.type = ShaderInputType::Buffer;
entry.bufferDesc.type = InputBufferType::RootConstantBuffer;
}
+ else if (parser.LookAhead("Uniform"))
+ {
+ entry.type = ShaderInputType::Uniform;
+ }
else if (parser.LookAhead("ubuffer"))
{
entry.type = ShaderInputType::Buffer;
@@ -226,6 +234,10 @@ namespace renderer_test
numRenderTargets = parser.ReadInt();
continue;
}
+ else
+ {
+ throw TextFormatException(String("Invalid input syntax at line ") + String(parser.NextToken().Position.Line));
+ }
parser.ReadToken();
// parse options
if (parser.LookAhead("("))
@@ -510,6 +522,11 @@ namespace renderer_test
parser.Read("=");
entry.textureDesc.mipMapCount = int(parser.ReadInt());
}
+ else if( word == "type" )
+ {
+ parser.Read("=");
+ entry.objectDesc.typeName = parser.ReadWord();
+ }
if (parser.LookAhead(","))
parser.Read(",");
diff --git a/tools/render-test/shader-input-layout.h b/tools/render-test/shader-input-layout.h
index 97796d7f6..437da820b 100644
--- a/tools/render-test/shader-input-layout.h
+++ b/tools/render-test/shader-input-layout.h
@@ -17,7 +17,8 @@ using namespace gfx;
enum class ShaderInputType
{
- Buffer, Texture, Sampler, CombinedTextureSampler, Array
+ Buffer, Texture, Sampler, CombinedTextureSampler, Array, Uniform,
+ Object,
};
enum class InputTextureContent
@@ -81,6 +82,11 @@ struct BindlessHandleDataEntry
Slang::String name;
};
+struct InputObjectDesc
+{
+ Slang::String typeName;
+};
+
class ShaderInputLayoutEntry
{
public:
@@ -92,6 +98,7 @@ public:
InputBufferDesc bufferDesc;
InputSamplerDesc samplerDesc;
ArrayDesc arrayDesc;
+ InputObjectDesc objectDesc;
bool isOutput = false;
bool onlyCPULikeBinding = false; ///< If true, only use on targets that have 'uniform' or 'CPU like' binding, like CPU and CUDA
bool isBindlessObject = false; ///< If true, this is a bindless object with no associated binding point in the shader.
diff --git a/tools/render-test/shader-renderer-util.cpp b/tools/render-test/shader-renderer-util.cpp
index b2911ffd5..5e77cf1fd 100644
--- a/tools/render-test/shader-renderer-util.cpp
+++ b/tools/render-test/shader-renderer-util.cpp
@@ -149,7 +149,7 @@ static SamplerState::Desc _calcSamplerDesc(const InputSamplerDesc& srcDesc)
return dstDesc;
}
-static RefPtr<SamplerState> _createSamplerState(
+RefPtr<SamplerState> _createSamplerState(
Renderer* renderer,
const InputSamplerDesc& srcDesc)
{
diff --git a/tools/render-test/shader-renderer-util.h b/tools/render-test/shader-renderer-util.h
index 872f21768..76f3b6d87 100644
--- a/tools/render-test/shader-renderer-util.h
+++ b/tools/render-test/shader-renderer-util.h
@@ -47,6 +47,10 @@ struct BindingStateImpl : public Slang::RefObject
int m_numRenderTargets = 1;
};
+RefPtr<SamplerState> _createSamplerState(
+ Renderer* renderer,
+ const InputSamplerDesc& srcDesc);
+
/// Utility class containing functions that construct items on the renderer using the ShaderInputLayout representation
struct ShaderRendererUtil
{
diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp
index 78c730cab..baa745b14 100644
--- a/tools/render-test/slang-support.cpp
+++ b/tools/render-test/slang-support.cpp
@@ -20,7 +20,7 @@ static const char fragmentEntryPointName[] = "fragmentMain";
static const char computeEntryPointName[] = "computeMain";
static const char rtEntryPointName[] = "raygenMain";
-static gfx::StageType _translateStage(SlangStage slangStage)
+gfx::StageType translateStage(SlangStage slangStage)
{
switch(slangStage)
{
@@ -50,12 +50,12 @@ static gfx::StageType _translateStage(SlangStage slangStage)
}
}
-/* static */ SlangResult ShaderCompilerUtil::compileProgram(SlangSession* session, const Options& options, const Input& input, const ShaderCompileRequest& request, Output& out)
+/* static */ SlangResult ShaderCompilerUtil::_compileProgramImpl(SlangSession* session, const Options& options, const Input& input, const ShaderCompileRequest& request, Output& out)
{
out.reset();
SlangCompileRequest* slangRequest = spCreateCompileRequest(session);
- out.request = slangRequest;
+ out.m_requestForKernels = slangRequest;
out.session = session;
// Parse all the extra args
@@ -215,7 +215,7 @@ static gfx::StageType _translateStage(SlangStage slangStage)
size_t codeSize = 0;
char const* code = (char const*) spGetEntryPointCode(slangRequest, int(ee), &codeSize);
- auto gfxStage = _translateStage(actualEntryPoint.slangStage);
+ auto gfxStage = translateStage(actualEntryPoint.slangStage);
ShaderProgram::KernelDesc kernelDesc;
kernelDesc.stage = gfxStage;
@@ -231,6 +231,58 @@ static gfx::StageType _translateStage(SlangStage slangStage)
return SLANG_OK;
}
+/* static */ SlangResult ShaderCompilerUtil::compileProgram(SlangSession* session, const Options& options, const Input& input, const ShaderCompileRequest& request, Output& out)
+{
+ if( input.passThrough == SLANG_PASS_THROUGH_NONE )
+ {
+ return _compileProgramImpl(session, options, input, request, out);
+ }
+ else
+ {
+ bool canUseSlangForPrecompile = false;
+ switch (input.passThrough)
+ {
+ case SLANG_PASS_THROUGH_DXC:
+ case SLANG_PASS_THROUGH_FXC:
+ canUseSlangForPrecompile = true;
+ break;
+ default:
+ break;
+ }
+ // If we are doing a HLSL pass-through compilation, then we can't rely
+ // on the downstream compiler for the reflection information that
+ // will drive all of our parameter binding. As such, we will first
+ // compile with Slang to get reflection information, and then
+ // compile in another pass using the desired downstream compiler
+ // so that we can get the refleciton information we need.
+ //
+ Output slangOutput;
+ if (canUseSlangForPrecompile)
+ {
+ ShaderCompilerUtil::Input slangInput = input;
+ slangInput.sourceLanguage = SLANG_SOURCE_LANGUAGE_SLANG;
+ slangInput.passThrough = SLANG_PASS_THROUGH_NONE;
+ // TODO: we want to pass along a flag to skip codegen...
+
+
+ SLANG_RETURN_ON_FAIL(_compileProgramImpl(session, options, slangInput, request, slangOutput));
+ }
+
+ // Now we have what we need to be able to do the downstream compile better.
+ //
+ // TODO: We should be able to use the output from the Slang compilation
+ // to fill in the actual entry points to be used for this compilation,
+ // so that discovery of entry points via `[shader(...)]` attributes will work.
+ //
+ SLANG_RETURN_ON_FAIL(_compileProgramImpl(session, options, input, request, out));
+
+ out.m_extraRequestForReflection = slangOutput.getRequestForReflection();
+ slangOutput.m_requestForKernels = nullptr;
+
+ return SLANG_OK;
+ }
+}
+
/* static */SlangResult ShaderCompilerUtil::readSource(const String& inSourcePath, List<char>& outSourceText)
{
// Read in the source code
diff --git a/tools/render-test/slang-support.h b/tools/render-test/slang-support.h
index 5e38c8c69..a0a7ef276 100644
--- a/tools/render-test/slang-support.h
+++ b/tools/render-test/slang-support.h
@@ -10,6 +10,8 @@
namespace renderer_test {
+gfx::StageType translateStage(SlangStage slangStage);
+
struct ShaderCompilerUtil
{
struct Input
@@ -42,19 +44,21 @@ struct ShaderCompilerUtil
}
kernelDescs.clear();
- if (request && session)
+ if (m_requestForKernels && session)
+ {
+ spDestroyCompileRequest(m_requestForKernels);
+ }
+ if (m_extraRequestForReflection && session)
{
- spDestroyCompileRequest(request);
+ spDestroyCompileRequest(m_extraRequestForReflection);
}
session = nullptr;
- request = nullptr;
+ m_requestForKernels = nullptr;
+ m_extraRequestForReflection = nullptr;
}
~Output()
{
- if (request && session)
- {
- spDestroyCompileRequest(request);
- }
+ reset();
}
Slang::Index findKernelDescIndex(gfx::StageType stage) const
@@ -71,7 +75,16 @@ struct ShaderCompilerUtil
List<ShaderProgram::KernelDesc> kernelDescs;
ShaderProgram::Desc desc;
- SlangCompileRequest* request = nullptr;
+
+ /// Compile request that owns the lifetime of compiled kernel code.
+ SlangCompileRequest* m_requestForKernels = nullptr;
+
+ /// Compile request that owns the lifetime of reflection information.
+ SlangCompileRequest* m_extraRequestForReflection = nullptr;
+
+ SlangCompileRequest* getRequestForKernels() const { return m_requestForKernels; }
+ SlangCompileRequest* getRequestForReflection() const { return m_extraRequestForReflection ? m_extraRequestForReflection : m_requestForKernels; }
+
SlangSession* session = nullptr;
};
@@ -87,6 +100,7 @@ struct ShaderCompilerUtil
static SlangResult readSource(const Slang::String& inSourcePath, List<char>& outSourceText);
+ static SlangResult _compileProgramImpl(SlangSession* session, const Options& options, const Input& input, const ShaderCompileRequest& request, Output& out);
static SlangResult compileProgram(SlangSession* session, const Options& options, const Input& input, const ShaderCompileRequest& request, Output& out);
};