summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/render-test/main.cpp20
-rw-r--r--tools/render-test/render-d3d11.cpp536
-rw-r--r--tools/render-test/render-d3d12.cpp414
-rw-r--r--tools/render-test/render-gl.cpp208
-rw-r--r--tools/render-test/render-vk.cpp554
-rw-r--r--tools/render-test/render.cpp128
-rw-r--r--tools/render-test/render.h156
-rw-r--r--tools/render-test/slang-support.cpp132
-rw-r--r--tools/render-test/slang-support.h8
9 files changed, 1204 insertions, 952 deletions
diff --git a/tools/render-test/main.cpp b/tools/render-test/main.cpp
index acc7ffb78..887ba4005 100644
--- a/tools/render-test/main.cpp
+++ b/tools/render-test/main.cpp
@@ -64,6 +64,8 @@ class RenderTestApp
BindingState* getBindingState() const { return m_bindingState; }
+ Result writeBindingOutput(const char* fileName);
+
protected:
/// Called in initialize
Result initializeShaders(ShaderCompiler* shaderCompiler);
@@ -99,7 +101,12 @@ SlangResult RenderTestApp::initialize(Renderer* renderer, ShaderCompiler* shader
m_renderer = renderer;
- m_bindingState = renderer->createBindingState(m_shaderInputLayout);
+ {
+ BindingState::Desc bindingStateDesc;
+ SLANG_RETURN_ON_FAIL(createBindingStateDesc(m_shaderInputLayout, m_renderer, bindingStateDesc));
+
+ m_bindingState = m_renderer->createBindingState(bindingStateDesc);
+ }
// Do other initialization that doesn't depend on the source language.
@@ -237,6 +244,11 @@ void RenderTestApp::finalize()
{
}
+Result RenderTestApp::writeBindingOutput(const char* fileName)
+{
+ return serializeBindingOutput(m_shaderInputLayout, m_bindingState, m_renderer, fileName);
+}
+
//
// We use a bare-minimum window procedure to get things up and running.
@@ -421,9 +433,13 @@ SlangResult innerMain(int argc, char** argv)
renderer->waitForGpu();
if (gOptions.shaderType == ShaderProgramType::Compute || gOptions.shaderType == ShaderProgramType::GraphicsCompute)
- renderer->serializeOutput(app.getBindingState(), gOptions.outputPath);
+ {
+ SLANG_RETURN_ON_FAIL(app.writeBindingOutput(gOptions.outputPath));
+ }
else
+ {
SLANG_RETURN_ON_FAIL(renderer->captureScreenShot(gOptions.outputPath));
+ }
return SLANG_OK;
}
diff --git a/tools/render-test/render-d3d11.cpp b/tools/render-test/render-d3d11.cpp
index 18e41db7e..a0c4956f2 100644
--- a/tools/render-test/render-d3d11.cpp
+++ b/tools/render-test/render-d3d11.cpp
@@ -9,8 +9,6 @@
#include <slang.h>
-#include "slang-support.h"
-
#include "../../source/core/slang-com-ptr.h"
#ifdef _MSC_VER
@@ -56,9 +54,8 @@ public:
virtual TextureResource* createTextureResource(Resource::Type type, Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override;
virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& bufferDesc, const void* initData) override;
virtual SlangResult captureScreenShot(char const* outputPath) override;
- virtual void serializeOutput(BindingState* state, const char* fileName) override;
virtual InputLayout* createInputLayout( const InputElementDesc* inputElements, UInt inputElementCount) override;
- virtual BindingState * createBindingState(const ShaderInputLayout& layout) override;
+ virtual BindingState* createBindingState(const BindingState::Desc& desc) override;
virtual ShaderCompiler* getShaderCompiler() override;
virtual void* map(BufferResource* buffer, MapFlavor flavor) override;
virtual void unmap(BufferResource* buffer) override;
@@ -78,27 +75,28 @@ public:
protected:
- struct Binding
+ struct BindingDetail
{
- ShaderInputType type;
- InputBufferType bufferType; // Only valid if `type` is `Buffer`
-
- ComPtr<ID3D11ShaderResourceView> srv;
- ComPtr<ID3D11UnorderedAccessView> uav;
- ComPtr<ID3D11SamplerState> samplerState;
-
- RefPtr<Resource> resource; /// Can hold texture of buffer
+ ComPtr<ID3D11ShaderResourceView> m_srv;
+ ComPtr<ID3D11UnorderedAccessView> m_uav;
+ ComPtr<ID3D11SamplerState> m_samplerState;
- int binding = 0;
- bool isOutput = false;
+ int m_binding = 0;
};
class BindingStateImpl: public BindingState
{
public:
- List<Binding> m_bindings;
- int m_numRenderTargets = 0;
+ typedef BindingState Parent;
+
+ /// Ctor
+ BindingStateImpl(const Desc& desc):
+ Parent(desc)
+ {}
+
+ List<BindingDetail> m_bindingDetails;
};
+
class ShaderProgramImpl: public ShaderProgram
{
public:
@@ -146,16 +144,6 @@ public:
/// Capture a texture to a file
static HRESULT captureTextureToFile(ID3D11Device* device, ID3D11DeviceContext* context, ID3D11Texture2D* texture, char const* outputPath);
- //void* map(ID3D11Buffer* buffer, MapFlavor flavor);
- //void unmap(ID3D11Buffer* buffer);
-
- Result createInputBuffer(const InputBufferDesc& bufferDesc, bool isOutput, const List<unsigned int>& bufferData,
- RefPtr<Resource>& resourceOut, ComPtr<ID3D11UnorderedAccessView>& viewOut, ComPtr<ID3D11ShaderResourceView>& srvOut);
-
- Result createInputTexture(const InputTextureDesc& inputDesc, RefPtr<Resource>& resourceOut, ComPtr<ID3D11ShaderResourceView>& viewOut);
-
- Result createInputSampler(const InputSamplerDesc& inputDesc, ComPtr<ID3D11SamplerState>& stateOut);
-
void applyBindingState(bool isCompute);
ComPtr<IDXGISwapChain> m_swapChain;
@@ -871,283 +859,284 @@ void D3D11Renderer::dispatchCompute(int x, int y, int z)
m_immediateContext->Dispatch(x, y, z);
}
-Result D3D11Renderer::createInputBuffer(const InputBufferDesc& bufferDesc, bool isOutput, const List<unsigned int>& bufferData,
- RefPtr<Resource>& resourceOut, ComPtr<ID3D11UnorderedAccessView>& viewOut, ComPtr<ID3D11ShaderResourceView>& srvOut)
+BindingState* D3D11Renderer::createBindingState(const BindingState::Desc& bindingStateDesc)
{
- const size_t bufferSize = bufferData.Count() * sizeof(unsigned int);
- RefPtr<BufferResource> bufferResource;
- SLANG_RETURN_ON_FAIL(createInputBufferResource(bufferDesc, isOutput, bufferSize, bufferData.Buffer(), this, bufferResource));
-
- BufferResourceImpl* bufferImpl = static_cast<BufferResourceImpl*>(bufferResource.Ptr());
-
- const int elemSize = bufferDesc.stride <= 0 ? 1 : bufferDesc.stride;
- if (bufferDesc.type == InputBufferType::StorageBuffer)
- {
- D3D11_UNORDERED_ACCESS_VIEW_DESC viewDesc;
- memset(&viewDesc, 0, sizeof(viewDesc));
- viewDesc.Buffer.FirstElement = 0;
- viewDesc.Buffer.NumElements = (UINT)(bufferData.Count() * sizeof(unsigned int) / elemSize);
- viewDesc.Buffer.Flags = 0;
- viewDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
- viewDesc.Format = DXGI_FORMAT_UNKNOWN;
-
- if (bufferDesc.stride == 0)
- {
- // TODO: are there UAV cases we need to handle that are neither
- // raw nor structured? RWBuffer<T> would be one...
+ RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc));
- viewDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_RAW;
- viewDesc.Format = DXGI_FORMAT_R32_TYPELESS;
- }
+ const auto& srcBindings = bindingStateDesc.m_bindings;
+ const int numBindings = int(srcBindings.Count());
+
+ auto& dstDetails = bindingState->m_bindingDetails;
+ dstDetails.SetSize(numBindings);
- SLANG_RETURN_ON_FAIL(m_device->CreateUnorderedAccessView(bufferImpl->m_buffer, &viewDesc, viewOut.writeRef()));
- }
- if (bufferDesc.type != InputBufferType::ConstantBuffer)
+ for (int i = 0; i < numBindings; ++i)
{
- D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
- memset(&srvDesc, 0, sizeof(srvDesc));
- srvDesc.Buffer.FirstElement = 0;
- srvDesc.Buffer.ElementWidth = elemSize;
- srvDesc.Buffer.NumElements = (UINT)(bufferData.Count() * sizeof(unsigned int) / elemSize);
- srvDesc.Buffer.ElementOffset = 0;
- srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
- srvDesc.Format = DXGI_FORMAT_UNKNOWN;
-
- if (bufferDesc.stride == 0)
- {
- srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
- }
-
- SLANG_RETURN_ON_FAIL(m_device->CreateShaderResourceView(bufferImpl->m_buffer, &srvDesc, srvOut.writeRef()));
- }
+ auto& dstDetail = dstDetails[i];
+ const auto& srcBinding = srcBindings[i];
+
+ dstDetail.m_binding = bindingStateDesc.getFirst(BindingState::ShaderStyle::Hlsl, srcBinding.registerDesc);
- resourceOut = bufferResource;
+ switch (srcBinding.bindingType)
+ {
+ case BindingType::Buffer:
+ {
+ assert(srcBinding.resource && srcBinding.resource->isBuffer());
- return SLANG_OK;
-}
+ BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
+ const BufferResource::Desc& bufferDesc = buffer->getDesc();
-Result D3D11Renderer::createInputTexture(const InputTextureDesc& inputDesc, RefPtr<Resource>& resourceOut, ComPtr<ID3D11ShaderResourceView>& viewOut)
-{
- ComPtr<ID3D11ShaderResourceView> view;
+ const int elemSize = bufferDesc.elementSize <= 0 ? 1 : bufferDesc.elementSize;
- int bindFlags = 0;
+ 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 = DXGI_FORMAT_UNKNOWN;
+
+ if (bufferDesc.elementSize == 0)
+ {
+ // TODO: are there UAV cases we need to handle that are neither
+ // raw nor structured? RWBuffer<T> would be one...
+
+ 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());
- RefPtr<TextureResource> texture;
- SLANG_RETURN_ON_FAIL(generateTextureResource(inputDesc, bindFlags, this, texture));
+ const TextureResource::Desc& textureDesc = texture->getDesc();
- //DXGI_FORMAT format = textureImpl->m_resource->GetD
- const TextureResource::Desc& textureDesc = texture->getDesc();
+ D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
+ viewDesc.Format = D3DUtil::getMapFormat(textureDesc.format);
- DXGI_FORMAT 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;
+ }
+ }
- TextureResourceImpl* textureImpl = static_cast<TextureResourceImpl*>(texture.Ptr());
+ 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];
- if (inputDesc.dimension == 1)
- {
- D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
- if (inputDesc.arrayLength != 0)
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
- viewDesc.Texture1D.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture1D.MostDetailedMip = 0;
- viewDesc.Texture1DArray.ArraySize = textureDesc.arraySize;
- viewDesc.Texture1DArray.FirstArraySlice = 0;
- viewDesc.Texture1DArray.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture1DArray.MostDetailedMip = 0;
- viewDesc.Format = format;
- m_device->CreateShaderResourceView(textureImpl->m_resource, &viewDesc, view.writeRef());
- }
- else if (inputDesc.dimension == 2)
- {
- D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
+ D3D11_SAMPLER_DESC desc = {};
+ desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
- if (inputDesc.isCube)
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
- viewDesc.TextureCube.MipLevels = textureDesc.numMipLevels;
- viewDesc.TextureCube.MostDetailedMip = 0;
- viewDesc.TextureCubeArray.MipLevels = textureDesc.numMipLevels;
- viewDesc.TextureCubeArray.MostDetailedMip = 0;
- viewDesc.TextureCubeArray.First2DArrayFace = 0;
- viewDesc.TextureCubeArray.NumCubes = inputDesc.arrayLength;
- }
- else
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
- viewDesc.Texture2D.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture2D.MostDetailedMip = 0;
- viewDesc.Texture2DArray.ArraySize = textureDesc.arraySize;
- viewDesc.Texture2DArray.FirstArraySlice = 0;
- viewDesc.Texture2DArray.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture2DArray.MostDetailedMip = 0;
+ 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;
+ }
}
- if (inputDesc.arrayLength != 0)
- viewDesc.ViewDimension = (D3D11_SRV_DIMENSION)(int)(viewDesc.ViewDimension + 1);
-
- viewDesc.Format = format;
-
- SLANG_RETURN_ON_FAIL(m_device->CreateShaderResourceView(textureImpl->m_resource, &viewDesc, view.writeRef()));
- }
- else if (inputDesc.dimension == 3)
- {
- D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
- viewDesc.Texture3D.MipLevels = 1;
- viewDesc.Texture3D.MostDetailedMip = 0;
- viewDesc.Format = format;
- m_device->CreateShaderResourceView(textureImpl->m_resource, &viewDesc, view.writeRef());
}
- resourceOut = texture;
- viewOut.swap(view);
- return SLANG_OK;
-}
-
-Result D3D11Renderer::createInputSampler(const InputSamplerDesc& inputDesc, ComPtr<ID3D11SamplerState>& stateOut)
-{
- D3D11_SAMPLER_DESC desc;
- memset(&desc, 0, sizeof(desc));
- desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
- if (inputDesc.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;
- }
- return m_device->CreateSamplerState(&desc, stateOut.writeRef());
+ // Done
+ return bindingState.detach();
}
-BindingState* D3D11Renderer::createBindingState(const ShaderInputLayout& layout)
+void D3D11Renderer::applyBindingState(bool isCompute)
{
- RefPtr<BindingStateImpl> bindingState(new BindingStateImpl);
+ auto context = m_immediateContext.get();
- const List<ShaderInputLayoutEntry>& srcBindings = layout.entries;
- const int numBindings = int(srcBindings.Count());
+ const auto& details = m_currentBindings->m_bindingDetails;
+ const auto& bindings = m_currentBindings->getDesc().m_bindings;
- List<Binding>& dstBindings = bindingState->m_bindings;
- dstBindings.SetSize(numBindings);
+ const int numBindings = int(bindings.Count());
- bindingState->m_numRenderTargets = layout.numRenderTargets;
-
for (int i = 0; i < numBindings; ++i)
{
- Binding& dstBinding = dstBindings[i];
- const ShaderInputLayoutEntry& srcBinding = srcBindings[i];
+ const auto& binding = bindings[i];
+ const auto& detail = details[i];
- dstBinding.type = srcBinding.type;
- dstBinding.binding = srcBinding.hlslBinding;
- dstBinding.isOutput = srcBinding.isOutput;
- switch (srcBinding.type)
+ switch (binding.bindingType)
{
- case ShaderInputType::Buffer:
- {
- SLANG_RETURN_NULL_ON_FAIL(createInputBuffer(srcBinding.bufferDesc, srcBinding.isOutput, srcBinding.bufferData, dstBinding.resource, dstBinding.uav, dstBinding.srv));
- dstBinding.bufferType = srcBinding.bufferDesc.type;
- break;
- }
- case ShaderInputType::Texture:
- {
- SLANG_RETURN_NULL_ON_FAIL(createInputTexture(srcBinding.textureDesc, dstBinding.resource, dstBinding.srv));
- break;
- }
- case ShaderInputType::Sampler:
- {
- SLANG_RETURN_NULL_ON_FAIL(createInputSampler(srcBinding.samplerDesc, dstBinding.samplerState));
- break;
- }
- case ShaderInputType::CombinedTextureSampler:
+ case BindingType::Buffer:
{
- assert(!"Not implemented");
- //throw "not implemented";
- return nullptr;
- break;
- }
- }
- }
-
- return bindingState.detach();
-}
-
-void D3D11Renderer::applyBindingState(bool isCompute)
-{
- auto context = m_immediateContext.get();
- for (auto & binding : m_currentBindings->m_bindings)
- {
- if (binding.type == ShaderInputType::Buffer)
- {
-
- if (binding.bufferType == InputBufferType::ConstantBuffer)
- {
- BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(binding.resource.Ptr());
- ID3D11Buffer* buffer = bufferResource->m_buffer;
-
- if (isCompute)
- context->CSSetConstantBuffers(binding.binding, 1, &buffer);
- else
+ assert(binding.resource && binding.resource->isBuffer());
+ if (binding.resource->canBind(Resource::BindFlag::ConstantBuffer))
{
- context->VSSetConstantBuffers(binding.binding, 1, &buffer);
- context->PSSetConstantBuffers(binding.binding, 1, &buffer);
+ ID3D11Buffer* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr())->m_buffer;
+ if (isCompute)
+ context->CSSetConstantBuffers(detail.m_binding, 1, &buffer);
+ else
+ {
+ context->VSSetConstantBuffers(detail.m_binding, 1, &buffer);
+ context->PSSetConstantBuffers(detail.m_binding, 1, &buffer);
+ }
+ }
+ else if (detail.m_uav)
+ {
+ if (isCompute)
+ context->CSSetUnorderedAccessViews(detail.m_binding, 1, detail.m_uav.readRef(), nullptr);
+ else
+ context->OMSetRenderTargetsAndUnorderedAccessViews(m_currentBindings->getDesc().m_numRenderTargets,
+ m_renderTargetViews.Buffer()->readRef(), nullptr, detail.m_binding, 1, detail.m_uav.readRef(), nullptr);
}
- }
- else if (binding.uav)
- {
- if (isCompute)
- context->CSSetUnorderedAccessViews(binding.binding, 1, binding.uav.readRef(), nullptr);
- else
- context->OMSetRenderTargetsAndUnorderedAccessViews(m_currentBindings->m_numRenderTargets,
- m_renderTargetViews.Buffer()->readRef(), nullptr, binding.binding, 1, binding.uav.readRef(), nullptr);
- }
- else
- {
- if (isCompute)
- context->CSSetShaderResources(binding.binding, 1, binding.srv.readRef());
else
{
- context->PSSetShaderResources(binding.binding, 1, binding.srv.readRef());
- context->VSSetShaderResources(binding.binding, 1, binding.srv.readRef());
+ if (isCompute)
+ context->CSSetShaderResources(detail.m_binding, 1, detail.m_srv.readRef());
+ else
+ {
+ context->PSSetShaderResources(detail.m_binding, 1, detail.m_srv.readRef());
+ context->VSSetShaderResources(detail.m_binding, 1, detail.m_srv.readRef());
+ }
}
+ break;
}
- }
- else if (binding.type == ShaderInputType::Texture)
- {
- if (binding.uav)
+ case BindingType::Texture:
{
- if (isCompute)
- context->CSSetUnorderedAccessViews(binding.binding, 1, binding.uav.readRef(), nullptr);
+ if (detail.m_uav)
+ {
+ if (isCompute)
+ context->CSSetUnorderedAccessViews(detail.m_binding, 1, detail.m_uav.readRef(), nullptr);
+ else
+ context->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL,
+ nullptr, nullptr, detail.m_binding, 1, detail.m_uav.readRef(), nullptr);
+ }
else
- context->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL,
- nullptr, nullptr, binding.binding, 1, binding.uav.readRef(), nullptr);
+ {
+ if (isCompute)
+ context->CSSetShaderResources(detail.m_binding, 1, detail.m_srv.readRef());
+ else
+ {
+ context->PSSetShaderResources(detail.m_binding, 1, detail.m_srv.readRef());
+ context->VSSetShaderResources(detail.m_binding, 1, detail.m_srv.readRef());
+ }
+ }
+ break;
}
- else
+ case BindingType::Sampler:
{
if (isCompute)
- context->CSSetShaderResources(binding.binding, 1, binding.srv.readRef());
+ context->CSSetSamplers(detail.m_binding, 1, detail.m_samplerState.readRef());
else
{
- context->PSSetShaderResources(binding.binding, 1, binding.srv.readRef());
- context->VSSetShaderResources(binding.binding, 1, binding.srv.readRef());
+ context->PSSetSamplers(detail.m_binding, 1, detail.m_samplerState.readRef());
+ context->VSSetSamplers(detail.m_binding, 1, detail.m_samplerState.readRef());
}
+ break;
}
- }
- else if (binding.type == ShaderInputType::Sampler)
- {
- if (isCompute)
- context->CSSetSamplers(binding.binding, 1, binding.samplerState.readRef());
- else
+ default:
{
- context->PSSetSamplers(binding.binding, 1, binding.samplerState.readRef());
- context->VSSetSamplers(binding.binding, 1, binding.samplerState.readRef());
+ assert(!"Not implemented");
+ return;
}
}
- else
- throw "not implemented";
}
}
@@ -1156,35 +1145,4 @@ void D3D11Renderer::setBindingState(BindingState* state)
m_currentBindings = static_cast<BindingStateImpl*>(state);
}
-void D3D11Renderer::serializeOutput(BindingState* stateIn, const char* fileName)
-{
- auto bindingState = static_cast<BindingStateImpl*>(stateIn);
- FILE * f = fopen(fileName, "wb");
- int id = 0;
- for (auto & binding : bindingState->m_bindings)
- {
- if (binding.isOutput)
- {
- if (binding.resource && binding.resource->isBuffer())
- {
- BufferResource* bufferResource = static_cast<BufferResource*>(binding.resource.Ptr());
- const size_t bufferSize = bufferResource->getDesc().sizeInBytes;
-
- unsigned int* ptr = (unsigned int*)map(bufferResource, MapFlavor::HostRead);
- for (auto i = 0u; i < bufferSize / sizeof(unsigned int); i++)
- {
- fprintf(f, "%X\n", ptr[i]);
- }
- unmap(bufferResource);
- }
- else
- {
- printf("invalid output type at %d.\n", id);
- }
- }
- id++;
- }
- fclose(f);
-}
-
} // renderer_test
diff --git a/tools/render-test/render-d3d12.cpp b/tools/render-test/render-d3d12.cpp
index 2d024396a..da2b3abd0 100644
--- a/tools/render-test/render-d3d12.cpp
+++ b/tools/render-test/render-d3d12.cpp
@@ -3,7 +3,6 @@
#include "options.h"
#include "render.h"
-#include "slang-support.h"
// In order to use the Slang API, we need to include its header
@@ -64,9 +63,8 @@ public:
virtual TextureResource* createTextureResource(Resource::Type type, Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override;
virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& bufferDesc, const void* initData) override;
virtual SlangResult captureScreenShot(const char* outputPath) override;
- virtual void serializeOutput(BindingState* state, const char* fileName) override;
virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override;
- virtual BindingState* createBindingState(const ShaderInputLayout& layout) override;
+ virtual BindingState* createBindingState(const BindingState::Desc& bindingStateDesc) override;
virtual ShaderCompiler* getShaderCompiler() override;
virtual void* map(BufferResource* buffer, MapFlavor flavor) override;
virtual void unmap(BufferResource* buffer) override;
@@ -204,23 +202,18 @@ protected:
List<char> m_text; ///< Holds all strings to keep in scope
};
- struct Binding
+ struct BindingDetail
{
- ShaderInputType m_type;
- InputBufferType m_bufferType; // Only valid if `type` is `Buffer`
int m_srvIndex = -1;
int m_uavIndex = -1;
- int m_samplerIndex = -1;
-
- RefPtr<Resource> m_resource;
-
+ int m_samplerIndex = -1;
int m_binding = 0;
- bool m_isOutput = false;
};
class BindingStateImpl: public BindingState
{
public:
+ typedef BindingState Parent;
Result init(ID3D12Device* device)
{
@@ -230,9 +223,13 @@ protected:
return SLANG_OK;
}
- List<Binding> m_bindings;
- int m_numRenderTargets = 0;
+ /// Ctor
+ BindingStateImpl(const Desc& desc) :
+ Parent(desc)
+ {}
+ List<BindingDetail> m_bindingDetails; ///< These match 1-1 to the bindings in the m_desc
+
D3D12DescriptorHeap m_viewHeap; ///< Cbv, Srv, Uav
D3D12DescriptorHeap m_samplerHeap; ///< Heap for samplers
};
@@ -331,11 +328,6 @@ protected:
Result createBuffer(const D3D12_RESOURCE_DESC& resourceDesc, const void* srcData, D3D12Resource& uploadResource, D3D12_RESOURCE_STATES finalState, D3D12Resource& resourceOut);
- Result createInputSampler(const InputSamplerDesc& inputDesc, D3D12DescriptorHeap& samplerHeap, int samplerIndex);
- Result createInputTexture(const InputTextureDesc& inputDesc, D3D12DescriptorHeap& viewHeap, int srvIndex, RefPtr<Resource>& resourceOut);
- Result createInputBuffer(InputBufferDesc& bufferDesc, bool isOutput, const List<unsigned int>& bufferData, D3D12DescriptorHeap& viewHeap, int uavIndex, int srvIndex,
- RefPtr<Resource>& resourceOut);
-
void beginRender();
void endRender();
@@ -491,30 +483,7 @@ D3D12Renderer::~D3D12Renderer()
}
}
-Result D3D12Renderer::createInputSampler(const InputSamplerDesc& inputDesc, D3D12DescriptorHeap& samplerHeap, int samplerIndex)
-{
- D3D12_SAMPLER_DESC desc = {};
- desc.AddressU = desc.AddressV = desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
- desc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
-
- if (inputDesc.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, samplerHeap.getCpuHandle(samplerIndex));
- return SLANG_OK;
-}
-
-static void _initSrvDesc(const InputTextureDesc& inputDesc, const D3D12_RESOURCE_DESC& desc, DXGI_FORMAT pixelFormat, D3D12_SHADER_RESOURCE_VIEW_DESC& descOut)
+static void _initSrvDesc(Resource::Type resourceType, const TextureResource::Desc& textureDesc, const D3D12_RESOURCE_DESC& desc, DXGI_FORMAT pixelFormat, D3D12_SHADER_RESOURCE_VIEW_DESC& descOut)
{
// create SRV
descOut = D3D12_SHADER_RESOURCE_VIEW_DESC();
@@ -536,13 +505,13 @@ static void _initSrvDesc(const InputTextureDesc& inputDesc, const D3D12_RESOURCE
descOut.Texture2D.PlaneSlice = 0;
descOut.Texture2D.ResourceMinLODClamp = 0.0f;
}
- else if (inputDesc.isCube)
+ else if (resourceType == Resource::Type::TextureCube)
{
- if (inputDesc.arrayLength > 1)
+ if (textureDesc.arraySize > 1)
{
descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
- descOut.TextureCubeArray.NumCubes = inputDesc.arrayLength;
+ descOut.TextureCubeArray.NumCubes = textureDesc.arraySize;
descOut.TextureCubeArray.First2DArrayFace = 0;
descOut.TextureCubeArray.MipLevels = desc.MipLevels;
descOut.TextureCubeArray.MostDetailedMip = 0;
@@ -654,103 +623,6 @@ Result D3D12Renderer::createBuffer(const D3D12_RESOURCE_DESC& resourceDesc, cons
return SLANG_OK;
}
-Result D3D12Renderer::createInputTexture(const InputTextureDesc& inputDesc, D3D12DescriptorHeap& viewHeap, int srvIndex, RefPtr<Resource>& resourceOut)
-{
- int bindFlags = 0;
- if (srvIndex >= 0)
- {
- bindFlags |= Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource;
- }
-
- RefPtr<TextureResource> texture;
- SLANG_RETURN_ON_FAIL(generateTextureResource(inputDesc, bindFlags, this, texture));
-
- TextureResourceImpl* textureImpl = static_cast<TextureResourceImpl*>(texture.Ptr());
-
- if (srvIndex >= 0)
- {
- const D3D12_RESOURCE_DESC resourceDesc = textureImpl->m_resource.getResource()->GetDesc();
- const DXGI_FORMAT pixelFormat = resourceDesc.Format;
-
- D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
- _initSrvDesc(inputDesc, resourceDesc, pixelFormat, srvDesc);
-
- // Copy to the descriptor
- m_device->CreateShaderResourceView(textureImpl->m_resource, &srvDesc, viewHeap.getCpuHandle(srvIndex));
- }
-
- resourceOut = texture.Ptr();
- return SLANG_OK;
-}
-
-Result D3D12Renderer::createInputBuffer(InputBufferDesc& bufferDesc, bool isOutput, const List<unsigned int>& bufferData, D3D12DescriptorHeap& viewHeap, int uavIndex, int srvIndex,
- RefPtr<Resource>& bufferOut)
-{
- const size_t bufferSize = bufferData.Count() * sizeof(unsigned int);
-
- RefPtr<BufferResource> resource;
- SLANG_RETURN_ON_FAIL(createInputBufferResource(bufferDesc, isOutput, bufferSize, bufferData.Buffer(), this, resource));
-
- BufferResourceImpl* resourceImpl = static_cast<BufferResourceImpl*>(resource.Ptr());
-
- const int elemSize = bufferDesc.stride <= 0 ? sizeof(uint32_t) : bufferDesc.stride;
-
- if (uavIndex >= 0)
- {
- assert(bufferDesc.type == InputBufferType::StorageBuffer);
-
- D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
-
- uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
- uavDesc.Format = DXGI_FORMAT_UNKNOWN;
-
- uavDesc.Buffer.StructureByteStride = elemSize;
-
- uavDesc.Buffer.FirstElement = 0;
- uavDesc.Buffer.NumElements = (UINT)(bufferData.Count() * sizeof(unsigned int) / elemSize);
- uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
-
- if (bufferDesc.stride == 0)
- {
- // TODO: are there UAV cases we need to handle that are neither
- // raw nor structured? RWBuffer<T> would be one...
- uavDesc.Buffer.Flags |= D3D12_BUFFER_UAV_FLAG_RAW;
- uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
-
- uavDesc.Buffer.StructureByteStride = 0;
- }
-
- m_device->CreateUnorderedAccessView(resourceImpl->m_resource, nullptr, &uavDesc, viewHeap.getCpuHandle(uavIndex));
- }
-
- if (srvIndex >= 0)
- {
- //bufferDesc.type != InputBufferType::ConstantBuffer
-
- 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)(bufferData.Count() * sizeof(unsigned int) / elemSize);
- srvDesc.Buffer.StructureByteStride = elemSize;
- srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
-
- if (bufferDesc.stride == 0)
- {
- srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
- }
-
- m_device->CreateShaderResourceView(resourceImpl->m_resource, &srvDesc, viewHeap.getCpuHandle(srvIndex));
- }
-
- bufferOut = resource.detach();
-
- return SLANG_OK;
-}
-
void D3D12Renderer::_resetCommandList()
{
const FrameInfo& frame = getFrame();
@@ -1020,7 +892,7 @@ Result D3D12Renderer::calcGraphicsPipelineState(ComPtr<ID3D12RootSignature>& sig
psoDesc.PrimitiveTopologyType = m_primitiveTopologyType;
{
- const int numRenderTargets = m_boundBindingState ? m_boundBindingState->m_numRenderTargets : 1;
+ const int numRenderTargets = m_boundBindingState ? m_boundBindingState->getDesc().m_numRenderTargets : 1;
psoDesc.DSVFormat = m_depthStencilFormat;
psoDesc.NumRenderTargets = numRenderTargets;
@@ -1222,33 +1094,46 @@ Result D3D12Renderer::_calcBindParameters(BindParameters& params)
if (m_boundBindingState)
{
const int numBoundConstantBuffers = numConstantBuffers;
- for (int i = 0; i < int(m_boundBindingState->m_bindings.Count()); i++)
+
+ 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 Binding& binding = m_boundBindingState->m_bindings[i];
+ const auto& binding = bindings[i];
+ const auto& detail = details[i];
- if (binding.m_type == ShaderInputType::Buffer && binding.m_bufferType == InputBufferType::ConstantBuffer)
+ if (binding.bindingType == BindingType::Buffer)
{
- // Make sure it's not overlapping the ones we just statically defined
- //assert(binding.m_binding < numBoundConstantBuffers);
+ 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_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 = binding.m_binding;
- descriptor.RegisterSpace = 0;
+ D3D12_ROOT_DESCRIPTOR& descriptor = param.Descriptor;
+ descriptor.ShaderRegister = detail.m_binding;
+ descriptor.RegisterSpace = 0;
- numConstantBuffers++;
+ numConstantBuffers++;
+ }
}
- if (binding.m_srvIndex >= 0)
+ if (detail.m_srvIndex >= 0)
{
D3D12_DESCRIPTOR_RANGE& range = params.nextRange();
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
range.NumDescriptors = 1;
- range.BaseShaderRegister = binding.m_binding;
+ range.BaseShaderRegister = detail.m_binding;
range.RegisterSpace = 0;
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
@@ -1262,13 +1147,13 @@ Result D3D12Renderer::_calcBindParameters(BindParameters& params)
table.pDescriptorRanges = &range;
}
- if (binding.m_uavIndex >= 0)
+ if (detail.m_uavIndex >= 0)
{
D3D12_DESCRIPTOR_RANGE& range = params.nextRange();
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
range.NumDescriptors = 1;
- range.BaseShaderRegister = binding.m_binding;
+ range.BaseShaderRegister = detail.m_binding;
range.RegisterSpace = 0;
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
@@ -1359,26 +1244,34 @@ Result D3D12Renderer::_bindRenderState(RenderState* renderState, ID3D12GraphicsC
if (bindingState)
{
D3D12DescriptorHeap& heap = bindingState->m_viewHeap;
+ const auto& details = bindingState->m_bindingDetails;
+ const auto& bindings = bindingState->getDesc().m_bindings;
+ const int numBindings = int(details.Count());
- for (int i = 0; i < int(bindingState->m_bindings.Count()); i++)
+ for (int i = 0; i < numBindings; i++)
{
- const Binding& binding = bindingState->m_bindings[i];
-
- if (binding.m_type == ShaderInputType::Buffer && binding.m_bufferType == InputBufferType::ConstantBuffer)
+ const auto& detail = details[i];
+ const auto& binding = bindings[i];
+
+ if (binding.bindingType == BindingType::Buffer)
{
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.m_resource.Ptr());
- buffer->bindConstantBufferView(m_circularResourceHeap, index++, submitter);
- numConstantBuffers++;
+ assert(binding.resource && binding.resource->isBuffer());
+ if (binding.resource->canBind(Resource::BindFlag::ConstantBuffer))
+ {
+ BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr());
+ buffer->bindConstantBufferView(m_circularResourceHeap, index++, submitter);
+ numConstantBuffers++;
+ }
}
- if (binding.m_srvIndex >= 0)
+ if (detail.m_srvIndex >= 0)
{
- submitter->setRootDescriptorTable(index++, heap.getGpuHandle(binding.m_srvIndex));
+ submitter->setRootDescriptorTable(index++, heap.getGpuHandle(detail.m_srvIndex));
}
- if (binding.m_uavIndex >= 0)
+ if (detail.m_uavIndex >= 0)
{
- submitter->setRootDescriptorTable(index++, heap.getGpuHandle(binding.m_uavIndex));
+ submitter->setRootDescriptorTable(index++, heap.getGpuHandle(detail.m_uavIndex));
}
}
}
@@ -2460,76 +2353,160 @@ void D3D12Renderer::dispatchCompute(int x, int y, int z)
commandList->Dispatch(x, y, z);
}
-BindingState* D3D12Renderer::createBindingState(const ShaderInputLayout& layout)
+BindingState* D3D12Renderer::createBindingState(const BindingState::Desc& bindingStateDesc)
{
- RefPtr<BindingStateImpl> bindingState(new BindingStateImpl);
+ RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc));
SLANG_RETURN_NULL_ON_FAIL(bindingState->init(m_device));
- bindingState->m_numRenderTargets = layout.numRenderTargets;
-
- const List<ShaderInputLayoutEntry>& srcBindings = layout.entries;
+
+ const auto& srcBindings = bindingStateDesc.m_bindings;
const int numBindings = int(srcBindings.Count());
- List<Binding>& dstBindings = bindingState->m_bindings;
- dstBindings.SetSize(numBindings);
+ auto& dstDetails = bindingState->m_bindingDetails;
+ dstDetails.SetSize(numBindings);
for (int i = 0; i < numBindings; ++i)
{
- ShaderInputLayoutEntry& srcEntry = srcBindings[i];
- Binding& dstEntry = dstBindings[i];
-
- dstEntry.m_type = srcEntry.type;
- dstEntry.m_binding = srcEntry.hlslBinding;
- dstEntry.m_isOutput = srcEntry.isOutput;
+ const auto& srcEntry = srcBindings[i];
+ auto& dstDetail = dstDetails[i];
- switch (srcEntry.type)
+ dstDetail.m_binding = bindingStateDesc.getFirst(srcEntry.registerDesc.registerSets[int(BindingState::ShaderStyle::Hlsl)]);
+
+ switch (srcEntry.bindingType)
{
- case ShaderInputType::Buffer:
+ case BindingType::Buffer:
{
+ assert(srcEntry.resource && srcEntry.resource->isBuffer());
+ BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcEntry.resource.Ptr());
+ const BufferResource::Desc& bufferDesc = 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 (srcEntry.bufferDesc.type == InputBufferType::StorageBuffer)
+ if (bufferDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
{
- dstEntry.m_uavIndex = bindingState->m_viewHeap.allocate();
- if (dstEntry.m_uavIndex < 0)
+ 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 = DXGI_FORMAT_UNKNOWN;
+
+ 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)
+ {
+ // TODO: are there UAV cases we need to handle that are neither
+ // raw nor structured? RWBuffer<T> would be one...
+ uavDesc.Buffer.Flags |= D3D12_BUFFER_UAV_FLAG_RAW;
+ uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
+
+ 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));
}
- SLANG_RETURN_NULL_ON_FAIL(createInputBuffer(srcEntry.bufferDesc, srcEntry.isOutput, srcEntry.bufferData, bindingState->m_viewHeap, dstEntry.m_uavIndex, dstEntry.m_srvIndex, dstEntry.m_resource));
-
- dstEntry.m_bufferType = srcEntry.bufferDesc.type;
break;
}
- case ShaderInputType::Texture:
+ case BindingType::Texture:
{
- dstEntry.m_srvIndex = bindingState->m_viewHeap.allocate();
+ assert(srcEntry.resource && srcEntry.resource->isTexture());
+
+ TextureResourceImpl* textureResource = static_cast<TextureResourceImpl*>(srcEntry.resource.Ptr());
- if (dstEntry.m_srvIndex < 0)
+ 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));
+ }
- SLANG_RETURN_NULL_ON_FAIL(createInputTexture(srcEntry.textureDesc, bindingState->m_viewHeap, dstEntry.m_srvIndex, dstEntry.m_resource));
break;
}
- case ShaderInputType::Sampler:
+ case BindingType::Sampler:
{
- dstEntry.m_samplerIndex = srcEntry.hlslBinding;
- bindingState->m_samplerHeap.placeAt(srcEntry.hlslBinding);
+ const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcEntry.descIndex];
+
+ const int samplerIndex = bindingStateDesc.getFirst(srcEntry.registerDesc.registerSets[int(BindingState::ShaderStyle::Hlsl)]);
+ 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));
- SLANG_RETURN_NULL_ON_FAIL(createInputSampler(srcEntry.samplerDesc, bindingState->m_samplerHeap, dstEntry.m_samplerIndex));
break;
}
- case ShaderInputType::CombinedTextureSampler:
+ case BindingType::CombinedTextureSampler:
{
assert(!"Not implemented");
- //throw "not implemented";
return nullptr;
- break;
}
}
}
@@ -2542,39 +2519,6 @@ void D3D12Renderer::setBindingState(BindingState* state)
m_boundBindingState = static_cast<BindingStateImpl*>(state);
}
-void D3D12Renderer::serializeOutput(BindingState* stateIn, const char* fileName)
-{
- auto bindingState = static_cast<BindingStateImpl*>(stateIn);
- FILE * f = fopen(fileName, "wb");
-
- int id = 0;
- for (auto & binding : bindingState->m_bindings)
- {
- if (binding.m_isOutput)
- {
- if (binding.m_resource && binding.m_resource->isBuffer())
- {
- BufferResource* bufferResource = static_cast<BufferResource*>(binding.m_resource.Ptr());
- const size_t bufferSize = bufferResource->getDesc().sizeInBytes;
-
- unsigned int* ptr = (unsigned int*)map(bufferResource, MapFlavor::HostRead);
-
- for (auto i = 0u; i < bufferSize / sizeof(unsigned int); i++)
- {
- fprintf(f, "%X\n", ptr[i]);
- }
- unmap(bufferResource);
- }
- else
- {
- printf("invalid output type at %d.\n", id);
- }
- }
- id++;
- }
- fclose(f);
-}
-
// ShaderCompiler interface
ShaderProgram* D3D12Renderer::compileProgram(const ShaderCompileRequest& request)
diff --git a/tools/render-test/render-gl.cpp b/tools/render-test/render-gl.cpp
index 27c3cdab4..8db963014 100644
--- a/tools/render-test/render-gl.cpp
+++ b/tools/render-test/render-gl.cpp
@@ -11,8 +11,6 @@
#include "core/secure-crt.h"
#include "external/stb/stb_image_write.h"
-#include "slang-support.h"
-
// TODO(tfoley): eventually we should be able to run these
// tests on non-Windows targets to confirm that cross-compilation
// at least *works* on those platforms...
@@ -87,9 +85,8 @@ public:
virtual TextureResource* createTextureResource(Resource::Type type, Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override;
virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData) override;
virtual SlangResult captureScreenShot(char const* outputPath) override;
- virtual void serializeOutput(BindingState* state, const char* fileName) override;
virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override;
- virtual BindingState * createBindingState(const ShaderInputLayout& layout) override;
+ virtual BindingState* createBindingState(const BindingState::Desc& bindingStateDesc) override;
virtual ShaderCompiler* getShaderCompiler() override;
virtual void* map(BufferResource* buffer, MapFlavor flavor) override;
virtual void unmap(BufferResource* buffer) override;
@@ -188,19 +185,20 @@ public:
GLuint m_handle;
};
- struct BindingEntry
+ struct BindingDetail
{
- ShaderInputType type;
- RefPtr<Resource> resource;
- GLuint samplerHandle = 0;
- List<int> binding;
- bool isOutput = false;
+ GLuint m_samplerHandle = 0;
+ int m_firstBinding; //< Holds binding index if not sampler (which has multiple, and can be read from the BindingState::Desc)
};
class BindingStateImpl: public BindingState
{
public:
- BindingStateImpl(GLRenderer* renderer):
+ typedef BindingState Parent;
+
+ /// Ctor
+ BindingStateImpl(const Desc& desc, GLRenderer* renderer):
+ Parent(desc),
m_renderer(renderer)
{
}
@@ -209,12 +207,12 @@ public:
{
if (m_renderer)
{
- m_renderer->destroyBindingEntries(m_entries.Buffer(), int(m_entries.Count()));
+ m_renderer->destroyBindingEntries(getDesc(), m_bindingDetails.Buffer());
}
}
GLRenderer* m_renderer;
- List<BindingEntry> m_entries;
+ List<BindingDetail> m_bindingDetails;
};
class ShaderProgramImpl : public ShaderProgram
@@ -251,14 +249,13 @@ public:
GLenum formatType; // such as GL_UNSIGNED_BYTE
};
- void destroyBindingEntries(const BindingEntry* entries, int numEntries);
+ void destroyBindingEntries(const BindingState::Desc& desc, const BindingDetail* details);
void bindBufferImpl(int target, UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets);
void flushStateForDraw();
GLuint loadShader(GLenum stage, char const* source);
void debugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message);
- void createInputSampler(BindingEntry& rs, InputSamplerDesc samplerDesc);
-
+
/// Returns GlPixelFormat::Unknown if not an equivalent
static GlPixelFormat _getGlPixelFormat(Format format);
@@ -497,44 +494,22 @@ GLuint GLRenderer::loadShader(GLenum stage, const char* source)
return shaderID;
}
-void GLRenderer::destroyBindingEntries(const BindingEntry* entries, int numEntries)
+void GLRenderer::destroyBindingEntries(const BindingState::Desc& desc, const BindingDetail* details)
{
- for (int i = 0; i < numEntries; ++i)
+ const auto& bindings = desc.m_bindings;
+ const int numBindings = int(bindings.Count());
+ for (int i = 0; i < numBindings; ++i)
{
- const BindingEntry& entry = entries[i];
- if (entry.type == ShaderInputType::Sampler && entry.samplerHandle != 0)
+ const auto& binding = bindings[i];
+ const auto& detail = details[i];
+
+ if (binding.bindingType == BindingType::Sampler && detail.m_samplerHandle != 0)
{
- glDeleteSamplers(1, &entry.samplerHandle);
+ glDeleteSamplers(1, &detail.m_samplerHandle);
}
}
}
-void GLRenderer::createInputSampler(BindingEntry& entry, InputSamplerDesc samplerDesc)
-{
- 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);
- }
-
- entry.samplerHandle = handle;
-}
-
// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!!
SlangResult GLRenderer::initialize(void* inWindowHandle)
@@ -937,37 +912,39 @@ void GLRenderer::dispatchCompute(int x, int y, int z)
glDispatchCompute(x, y, z);
}
-BindingState* GLRenderer::createBindingState(const ShaderInputLayout& layout)
+BindingState* GLRenderer::createBindingState(const BindingState::Desc& bindingStateDesc)
{
- BindingStateImpl* state = new BindingStateImpl(this);
- for (auto & srcEntry : layout.entries)
+ 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)
{
- BindingEntry dstEntry;
- dstEntry.isOutput = srcEntry.isOutput;
- dstEntry.binding = srcEntry.glslBinding;
- dstEntry.type = srcEntry.type;
+ auto& dstDetail = dstDetails[i];
+ const auto& srcBinding = srcBindings[i];
- switch (srcEntry.type)
+ // Copy over the bindings
+ dstDetail.m_firstBinding = bindingStateDesc.getFirst(BindingState::ShaderStyle::Glsl, srcBinding.registerDesc);
+
+ switch (srcBinding.bindingType)
{
- case ShaderInputType::Buffer:
+ case BindingType::Texture:
+ case BindingType::Buffer:
{
- RefPtr<BufferResource> bufferResource;
- SLANG_RETURN_NULL_ON_FAIL(createInputBufferResource(srcEntry.bufferDesc, srcEntry.isOutput, srcEntry.bufferData.Count() * sizeof(uint32_t), srcEntry.bufferData.Buffer(), this, bufferResource));
- dstEntry.resource = bufferResource;
break;
}
- case ShaderInputType::Texture:
- case ShaderInputType::CombinedTextureSampler:
+ case BindingType::CombinedTextureSampler:
{
- RefPtr<TextureResource> textureResource;
+ assert(srcBinding.resource && srcBinding.resource->isTexture());
+ TextureResourceImpl* texture = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr());
+ const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex];
- int bindFlags = 0;
- SLANG_RETURN_NULL_ON_FAIL(generateTextureResource(srcEntry.textureDesc, bindFlags, this, textureResource));
-
- // Handle if combined
- if (srcEntry.type == ShaderInputType::CombinedTextureSampler && srcEntry.samplerDesc.isCompareSampler)
+ if (samplerDesc.isCompareSampler)
{
- TextureResourceImpl* texture = static_cast<TextureResourceImpl*>(textureResource.Ptr());
auto target = texture->m_target;
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -975,47 +952,80 @@ BindingState* GLRenderer::createBindingState(const ShaderInputLayout& layout)
glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
}
-
break;
}
- case ShaderInputType::Sampler:
+ case BindingType::Sampler:
{
- createInputSampler(dstEntry, srcEntry.samplerDesc);
+ 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;
}
}
- state->m_entries.Add(dstEntry);
}
- return state;
+
+ return bindingState.detach();
}
void GLRenderer::setBindingState(BindingState* stateIn)
{
BindingStateImpl* state = static_cast<BindingStateImpl*>(stateIn);
- for (auto & entry : state->m_entries)
+
+ 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)
{
- switch (entry.type)
+ const auto& binding = bindings[i];
+ const auto& detail = details[i];
+
+ switch (binding.bindingType)
{
- case ShaderInputType::Buffer:
+ case BindingType::Buffer:
{
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(entry.resource.Ptr());
- glBindBufferBase(buffer->m_target, entry.binding[0], buffer->m_handle);
+ BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr());
+ glBindBufferBase(buffer->m_target, detail.m_firstBinding, buffer->m_handle);
break;
}
- case ShaderInputType::Sampler:
+ case BindingType::Sampler:
{
- for (auto b : entry.binding)
+ auto bindings = bindingDesc.asRegisterList(BindingState::ShaderStyle::Glsl, binding.registerDesc);
+ for (auto b : bindings)
{
- glBindSampler(b, entry.samplerHandle);
+ glBindSampler(b, detail.m_samplerHandle);
}
break;
}
- case ShaderInputType::Texture:
- case ShaderInputType::CombinedTextureSampler:
+ case BindingType::Texture:
+ case BindingType::CombinedTextureSampler:
{
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(entry.resource.Ptr());
+ BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr());
- glActiveTexture(GL_TEXTURE0 + entry.binding[0]);
+ glActiveTexture(GL_TEXTURE0 + detail.m_firstBinding);
glBindTexture(buffer->m_target, buffer->m_handle);
break;
}
@@ -1023,34 +1033,6 @@ void GLRenderer::setBindingState(BindingState* stateIn)
}
}
-void GLRenderer::serializeOutput(BindingState* stateIn, const char* fileName)
-{
- BindingStateImpl * state = (BindingStateImpl*)stateIn;
- FILE * f;
- fopen_s(&f, fileName, "wt");
- for (auto & entry : state->m_entries)
- {
- if (entry.isOutput)
- {
- if (entry.resource && entry.resource->isBuffer())
- {
- BufferResource* bufferResource = static_cast<BufferResource*>(entry.resource.Ptr());
- size_t bufferSize = bufferResource->getDesc().sizeInBytes;
-
- unsigned int* ptr = (unsigned int*)map(bufferResource, MapFlavor::HostRead);
-
- for (auto i = 0u; i < bufferSize / sizeof(unsigned int); i++)
- {
- fprintf(f, "%X\n", ptr[i]);
- }
- unmap(bufferResource);
- }
- }
- }
- fclose(f);
-}
-
-
// ShaderCompiler interface
ShaderProgram* GLRenderer::compileProgram(const ShaderCompileRequest& request)
diff --git a/tools/render-test/render-vk.cpp b/tools/render-test/render-vk.cpp
index 13e67c132..68d933d92 100644
--- a/tools/render-test/render-vk.cpp
+++ b/tools/render-test/render-vk.cpp
@@ -92,9 +92,8 @@ public:
virtual TextureResource* createTextureResource(Resource::Type type, Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override;
virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& bufferDesc, const void* initData) override;
virtual SlangResult captureScreenShot(const char* outputPath) override;
- virtual void serializeOutput(BindingState* state, const char * fileName) override;
virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override;
- virtual BindingState * createBindingState(const ShaderInputLayout& layout) override;
+ virtual BindingState* createBindingState(const BindingState::Desc& bindingStateDesc) override;
virtual ShaderCompiler* getShaderCompiler() override;
virtual void* map(BufferResource* buffer, MapFlavor flavor) override;
virtual void unmap(BufferResource* buffer) override;
@@ -114,35 +113,53 @@ public:
protected:
+ class Buffer
+ {
+ public:
+
+ /// Returns true if has been initialized
+ bool isInitialized() const { return m_renderer != nullptr; }
+
+ // Default Ctor
+ Buffer():
+ m_renderer(nullptr)
+ {}
+
+ /// Dtor
+ ~Buffer()
+ {
+ if (m_renderer)
+ {
+ m_renderer->vkDestroyBuffer(m_renderer->m_device, m_buffer, nullptr);
+ m_renderer->vkFreeMemory(m_renderer->m_device, m_memory, nullptr);
+ }
+ }
+
+ VkBuffer m_buffer;
+ VkDeviceMemory m_memory;
+ VKRenderer* m_renderer;
+ };
+
class BufferResourceImpl: public BufferResource
{
public:
typedef BufferResource Parent;
- BufferResourceImpl(Resource::Usage initialUsage, const BufferResource::Desc& desc, VKRenderer* renderer, VkBuffer buffer, VkDeviceMemory memory):
+ BufferResourceImpl(Resource::Usage initialUsage, const BufferResource::Desc& desc, VKRenderer* renderer):
Parent(desc),
m_renderer(renderer),
- m_buffer(buffer),
- m_memory(memory),
m_initialUsage(initialUsage)
{
assert(renderer);
}
- ~BufferResourceImpl()
- {
- // Now destroy the staging buffer
- if (m_renderer)
- {
- m_renderer->vkDestroyBuffer(m_renderer->m_device, m_buffer, nullptr);
- m_renderer->vkFreeMemory(m_renderer->m_device, m_memory, nullptr);
- }
- }
-
Resource::Usage m_initialUsage;
- VKRenderer* m_renderer;
- VkBuffer m_buffer;
- VkDeviceMemory m_memory;
+ VKRenderer* m_renderer;
+ Buffer m_buffer;
+ Buffer m_uploadBuffer;
+ List<uint8_t> m_readBuffer; ///< Stores the contents when a map read is performed
+
+ MapFlavor m_mapFlavor = MapFlavor::Unknown; ///< If resource is mapped, records what kind of mapping else Unknown (if not mapped)
};
class ShaderProgramImpl: public ShaderProgram
@@ -156,33 +173,27 @@ public:
List<char> m_buffers[2]; //< To keep storage of code in scope
};
- struct Binding
+ struct BindingDetail
{
- ShaderInputType type;
- InputBufferType bufferType; // Only valid if `type` is `Buffer`
-
- VkImageView srv;
- VkBufferView uav;
- VkBuffer buffer;
- VkSampler samplerState;
-
- int binding = 0;
- bool isOutput = false;
- int bufferLength = 0;
+ VkImageView m_srv;
+ VkBufferView m_uav;
+ VkSampler m_samplerState;
+ int m_binding = 0;
};
class BindingStateImpl: public BindingState
{
public:
- BindingStateImpl(VKRenderer* renderer):
- m_renderer(renderer),
- m_numRenderTargets(0)
+ typedef BindingState Parent;
+
+ BindingStateImpl(const Desc& desc, VKRenderer* renderer):
+ Parent(desc),
+ m_renderer(renderer)
{
}
VKRenderer* m_renderer;
- List<Binding> m_bindings;
- int m_numRenderTargets;
+ List<BindingDetail> m_bindingDetails;
};
class InputLayoutImpl: public InputLayout
@@ -192,8 +203,7 @@ public:
VkBool32 handleDebugMessage(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg);
- BufferResourceImpl* createBufferResourceImpl(Resource::Usage initialUsage, const BufferResource::Desc& desc, size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, const void* initData = nullptr);
-
+
VkCommandBuffer getCommandBuffer();
VkCommandBuffer beginCommandBuffer();
void flushCommandBuffer(VkCommandBuffer commandBuffer);
@@ -202,10 +212,7 @@ public:
VkPipelineShaderStageCreateInfo compileEntryPoint(const ShaderCompileRequest::EntryPoint& entryPointRequest, VkShaderStageFlagBits stage, List<char>& bufferOut);
- void createInputTexture(const InputTextureDesc& inputDesc, VkImageView& viewOut);
- void createInputSampler(const InputSamplerDesc& inputDesc, VkSampler& stateOut);
- void createInputBuffer(const ShaderInputLayoutEntry& entry, const InputBufferDesc& bufferDesc, const Slang::List<unsigned int>& bufferData,
- VkBuffer& bufferOut, VkBufferView& uavOut, VkImageView& srvOut);
+ SlangResult _initBuffer(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, Buffer& bufferOut);
static SlangResult toSlangResult(VkResult res);
static void checkResult(VkResult result);
@@ -320,23 +327,22 @@ void VKRenderer::flushCommandBuffer(VkCommandBuffer commandBuffer)
vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer);
}
-VKRenderer::BufferResourceImpl* VKRenderer::createBufferResourceImpl(Resource::Usage initialUsage, const BufferResource::Desc& desc, size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, const void* initData)
+SlangResult VKRenderer::_initBuffer(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, Buffer& bufferOut)
{
- if (initData)
- {
- // TODO: what if we are allocating it as CPU-writable anyway?
- usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
- }
+ assert(!bufferOut.isInitialized());
+ bufferOut.m_renderer = this;
+ bufferOut.m_memory = 0;
+ bufferOut.m_buffer = 0;
+
VkBufferCreateInfo bufferCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufferCreateInfo.size = bufferSize;
bufferCreateInfo.usage = usage;
- VkBuffer buffer;
- checkResult(vkCreateBuffer(m_device, &bufferCreateInfo, nullptr, &buffer));
+ checkResult(vkCreateBuffer(m_device, &bufferCreateInfo, nullptr, &bufferOut.m_buffer));
VkMemoryRequirements memoryReqs = {};
- vkGetBufferMemoryRequirements(m_device, buffer, &memoryReqs);
+ vkGetBufferMemoryRequirements(m_device, bufferOut.m_buffer, &memoryReqs);
uint32_t memoryTypeIndex = getMemoryTypeIndex(memoryReqs.memoryTypeBits, reqMemoryProperties);
@@ -346,37 +352,10 @@ VKRenderer::BufferResourceImpl* VKRenderer::createBufferResourceImpl(Resource::U
allocateInfo.allocationSize = memoryReqs.size;
allocateInfo.memoryTypeIndex = memoryTypeIndex;
- VkDeviceMemory memory;
- checkResult(vkAllocateMemory(m_device, &allocateInfo, nullptr, &memory));
-
- checkResult(vkBindBufferMemory(m_device, buffer, memory, 0));
-
- if (initData)
- {
- // TODO: only create staging buffer if the memory type
- // used for the buffer doesn't let us fill things in
- // directly.
-
- RefPtr<BufferResourceImpl> staging = createBufferResourceImpl(initialUsage, desc, bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+ checkResult(vkAllocateMemory(m_device, &allocateInfo, nullptr, &bufferOut.m_memory));
+ checkResult(vkBindBufferMemory(m_device, bufferOut.m_buffer, bufferOut.m_memory, 0));
- // Copy into staging buffer
- void* mappedData = nullptr;
- checkResult(vkMapMemory(m_device, staging->m_memory, 0, bufferSize, 0, &mappedData));
- memcpy(mappedData, initData, bufferSize);
- vkUnmapMemory(m_device, staging->m_memory);
-
- // Copy from staging buffer to real buffer
- VkCommandBuffer commandBuffer = beginCommandBuffer();
-
- VkBufferCopy copyInfo = {};
- copyInfo.size = bufferSize;
- vkCmdCopyBuffer(commandBuffer, staging->m_buffer, buffer, 1, &copyInfo);
-
- flushCommandBuffer(commandBuffer);
- }
-
- return new BufferResourceImpl(initialUsage, desc, this, buffer, memory);
+ return SLANG_OK;
}
uint32_t VKRenderer::getMemoryTypeIndex(uint32_t inTypeBits, VkMemoryPropertyFlags properties)
@@ -397,78 +376,6 @@ uint32_t VKRenderer::getMemoryTypeIndex(uint32_t inTypeBits, VkMemoryPropertyFla
return uint32_t(-1);
}
-void VKRenderer::createInputTexture(const InputTextureDesc& inputDesc, VkImageView& viewOut)
-{
- TextureData texData;
- generateTextureData(texData, inputDesc);
- assert(!"unimplemented");
-}
-
-void VKRenderer::createInputSampler(const InputSamplerDesc& inputDesc, VkSampler& stateOut)
-{
- assert(!"unimplemented");
-}
-
-void VKRenderer::createInputBuffer(const ShaderInputLayoutEntry& entry, const InputBufferDesc& bufferDesc, const Slang::List<unsigned int>& bufferData,
- VkBuffer& bufferOut, VkBufferView& uavOut, VkImageView& srvOut)
-{
- size_t bufferSize = bufferData.Count() * sizeof(unsigned int);
- void const* initData = bufferData.Buffer();
-
- VkBufferUsageFlags usage = 0;
- VkMemoryPropertyFlags reqMemoryProperties = 0;
-
- Resource::Usage initialUsage = Resource::Usage::Unknown;
- switch (bufferDesc.type)
- {
- case InputBufferType::ConstantBuffer:
- usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
- reqMemoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
- initialUsage = Resource::Usage::ConstantBuffer;
- break;
-
- case InputBufferType::StorageBuffer:
- usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
- reqMemoryProperties = 0;
- initialUsage = Resource::Usage::PixelShaderResource;
- break;
- }
-
- BufferResource::Desc bufferResourceDesc;
-
- bufferResourceDesc.cpuAccessFlags = (entry.isOutput) ? Resource::AccessFlag::Read : 0;
- bufferResourceDesc.bindFlags = Resource::s_requiredBinding[int(initialUsage)];
- bufferResourceDesc.elementSize = 0;
- bufferResourceDesc.sizeInBytes = bufferSize;
-
- // If we are going to read back from the buffer, be sure to request
- // the required access.
- if (entry.isOutput)
- {
- usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
- }
-
- RefPtr<BufferResourceImpl> bufferImpl(createBufferResourceImpl(initialUsage, bufferResourceDesc, bufferSize, usage, reqMemoryProperties, initData));
-
- // TODO: need to hang onto the `memory` field so
- // that we can release it when we are done.
- // Set the m_renderer to null to stop any destruction as bufferImpl leaves scope
- bufferImpl->m_renderer = nullptr;
- bufferOut = bufferImpl->m_buffer;
-
- // Fill in any views needed
- switch (bufferDesc.type)
- {
- case InputBufferType::ConstantBuffer:
- break;
-
- case InputBufferType::StorageBuffer:
- {
- }
- break;
- }
-}
-
VkPipelineShaderStageCreateInfo VKRenderer::compileEntryPoint(const ShaderCompileRequest::EntryPoint& entryPointRequest, VkShaderStageFlagBits stage, List<char>& bufferOut)
{
char const* dataBegin = entryPointRequest.source.dataBegin;
@@ -749,7 +656,7 @@ BufferResource* VKRenderer::createBufferResource(Resource::Usage initialUsage, c
// If it can be read from, set this
usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
}
- if (desc.cpuAccessFlags & Resource::AccessFlag::Write)
+ if ((desc.cpuAccessFlags & Resource::AccessFlag::Write) || initData)
{
usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
}
@@ -764,7 +671,36 @@ BufferResource* VKRenderer::createBufferResource(Resource::Usage initialUsage, c
default: break;
}
- return createBufferResourceImpl(initialUsage, desc, bufferSize, usage, reqMemoryProperties, initData);
+ RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(initialUsage, desc, this));
+ SLANG_RETURN_NULL_ON_FAIL(_initBuffer(desc.sizeInBytes, usage, reqMemoryProperties, buffer->m_buffer));
+
+ if ((desc.cpuAccessFlags & Resource::AccessFlag::Write) || initData)
+ {
+ SLANG_RETURN_NULL_ON_FAIL(_initBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, buffer->m_uploadBuffer));
+ }
+
+ if (initData)
+ {
+ // TODO: only create staging buffer if the memory type
+ // used for the buffer doesn't let us fill things in
+ // directly.
+ // Copy into staging buffer
+ void* mappedData = nullptr;
+ checkResult(vkMapMemory(m_device, buffer->m_uploadBuffer.m_memory, 0, bufferSize, 0, &mappedData));
+ memcpy(mappedData, initData, bufferSize);
+ vkUnmapMemory(m_device, buffer->m_uploadBuffer.m_memory);
+
+ // Copy from staging buffer to real buffer
+ VkCommandBuffer commandBuffer = beginCommandBuffer();
+
+ VkBufferCopy copyInfo = {};
+ copyInfo.size = bufferSize;
+ vkCmdCopyBuffer(commandBuffer, buffer->m_uploadBuffer.m_buffer, buffer->m_buffer.m_buffer, 1, &copyInfo);
+
+ flushCommandBuffer(commandBuffer);
+ }
+
+ return buffer.detach();
}
InputLayout* VKRenderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount)
@@ -776,13 +712,90 @@ InputLayout* VKRenderer::createInputLayout(const InputElementDesc* inputElements
return (InputLayout*)impl;
}
-void* VKRenderer::map(BufferResource* buffer, MapFlavor flavor)
+void* VKRenderer::map(BufferResource* bufferIn, MapFlavor flavor)
{
- return nullptr;
+ BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn);
+ assert(buffer->m_mapFlavor == MapFlavor::Unknown);
+
+ const size_t bufferSize = buffer->getDesc().sizeInBytes;
+
+ switch (flavor)
+ {
+ case MapFlavor::WriteDiscard:
+ case MapFlavor::HostWrite:
+ {
+ if (!buffer->m_uploadBuffer.isInitialized())
+ {
+ return nullptr;
+ }
+
+ void* mappedData = nullptr;
+ checkResult(vkMapMemory(m_device, buffer->m_uploadBuffer.m_memory, 0, bufferSize, 0, &mappedData));
+ buffer->m_mapFlavor = flavor;
+ return mappedData;
+ }
+ case MapFlavor::HostRead:
+ {
+ // Make sure there is space in the read buffer
+ buffer->m_readBuffer.SetSize(bufferSize);
+
+ // create staging buffer
+ Buffer staging;
+
+ SLANG_RETURN_NULL_ON_FAIL(_initBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, staging));
+
+ // Copy from real buffer to staging buffer
+ VkCommandBuffer commandBuffer = beginCommandBuffer();
+
+ VkBufferCopy copyInfo = {};
+ copyInfo.size = bufferSize;
+ vkCmdCopyBuffer(commandBuffer, buffer->m_buffer.m_buffer, staging.m_buffer, 1, &copyInfo);
+
+ flushCommandBuffer(commandBuffer);
+
+ // Write out the data from the buffer
+ void* mappedData = nullptr;
+ checkResult(vkMapMemory(m_device, staging.m_memory, 0, bufferSize, 0, &mappedData));
+
+ ::memcpy(buffer->m_readBuffer.Buffer(), mappedData, bufferSize);
+ vkUnmapMemory(m_device, staging.m_memory);
+
+ return buffer->m_readBuffer.Buffer();
+ }
+ default:
+ return nullptr;
+ }
}
-void VKRenderer::unmap(BufferResource* buffer)
+void VKRenderer::unmap(BufferResource* bufferIn)
{
+ BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn);
+ assert(buffer->m_mapFlavor != MapFlavor::Unknown);
+
+ const size_t bufferSize = buffer->getDesc().sizeInBytes;
+
+ switch (buffer->m_mapFlavor)
+ {
+ case MapFlavor::WriteDiscard:
+ case MapFlavor::HostWrite:
+ {
+ vkUnmapMemory(m_device, buffer->m_uploadBuffer.m_memory);
+
+ // Copy from staging buffer to real buffer
+ VkCommandBuffer commandBuffer = beginCommandBuffer();
+
+ VkBufferCopy copyInfo = {};
+ copyInfo.size = bufferSize;
+ vkCmdCopyBuffer(commandBuffer, buffer->m_uploadBuffer.m_buffer, buffer->m_buffer.m_buffer, 1, &copyInfo);
+
+ flushCommandBuffer(commandBuffer);
+ break;
+ }
+ default: break;
+ }
+
+ // Mark as no longer mapped
+ buffer->m_mapFlavor = MapFlavor::Unknown;
}
void VKRenderer::setInputLayout(InputLayout* inputLayout)
@@ -810,45 +823,47 @@ void VKRenderer::draw(UInt vertexCount, UInt startVertex = 0)
{
}
-BindingState* VKRenderer::createBindingState(const ShaderInputLayout& layout)
-{
- BindingStateImpl* bindingState = new BindingStateImpl(this);
- bindingState->m_numRenderTargets = layout.numRenderTargets;
- for (auto & entry : layout.entries)
+BindingState* VKRenderer::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)
{
- Binding binding;
- binding.type = entry.type;
- binding.binding = entry.hlslBinding;
- binding.isOutput = entry.isOutput;
- switch (entry.type)
+ auto& dstDetail = dstDetails[i];
+ const auto& srcBinding = srcBindings[i];
+
+ // For now use Glsl binding
+ dstDetail.m_binding = bindingStateDesc.getFirst(BindingState::ShaderStyle::Glsl, srcBinding.registerDesc);
+
+ switch (srcBinding.bindingType)
{
- case ShaderInputType::Buffer:
+ case BindingType::Buffer:
{
- createInputBuffer(entry, entry.bufferDesc, entry.bufferData, binding.buffer, binding.uav, binding.srv);
- binding.bufferLength = (int)(entry.bufferData.Count() * sizeof(unsigned int));
- binding.bufferType = entry.bufferDesc.type;
- }
- break;
- case ShaderInputType::Texture:
- {
- createInputTexture(entry.textureDesc, binding.srv);
- break;
- }
- case ShaderInputType::Sampler:
- {
- createInputSampler(entry.samplerDesc, binding.samplerState);
+ assert(srcBinding.resource && srcBinding.resource->isBuffer());
+ //BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
+ //const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc();
+
+ // TODO: Setup views.
+ // VkBufferView uav
+ // VkImageView srv
break;
}
- case ShaderInputType::CombinedTextureSampler:
+ case BindingType::Texture:
+ case BindingType::Sampler:
+ case BindingType::CombinedTextureSampler:
{
- throw "not implemented";
- break;
+ assert(!"not implemented");
}
}
- bindingState->m_bindings.Add(binding);
}
- return bindingState;
+ return bindingState.detach();;
}
void VKRenderer::setBindingState(BindingState* state)
@@ -856,96 +871,43 @@ void VKRenderer::setBindingState(BindingState* state)
m_currentBindingState = static_cast<BindingStateImpl*>(state);
}
-void VKRenderer::serializeOutput(BindingState* s, const char* fileName)
-{
- auto state = static_cast<BindingStateImpl*>(s);
-
- FILE * f = fopen(fileName, "wb");
- int id = 0;
- for (auto& bb : state->m_bindings)
- {
- if (bb.isOutput)
- {
- if (bb.buffer)
- {
- Resource::Usage initialUsage = Resource::Usage::NonPixelShaderResource;
- BufferResource::Desc bufferResourceDesc;
-
- size_t bufferSize = bb.bufferLength;
-
- bufferResourceDesc.cpuAccessFlags = Resource::AccessFlag::Read;
- bufferResourceDesc.bindFlags = 0;
- bufferResourceDesc.elementSize = 0;
- bufferResourceDesc.sizeInBytes = bufferSize;
-
- // create staging buffer
- RefPtr<BufferResourceImpl> staging(createBufferResourceImpl(initialUsage, bufferResourceDesc, bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
-
- // Copy from real buffer to staging buffer
- VkCommandBuffer commandBuffer = beginCommandBuffer();
-
- VkBufferCopy copyInfo = {};
- copyInfo.size = bufferSize;
- vkCmdCopyBuffer(commandBuffer, bb.buffer, staging->m_buffer, 1, &copyInfo);
-
- flushCommandBuffer(commandBuffer);
-
- // Write out the data from the buffer
- void* mappedData = nullptr;
- checkResult(vkMapMemory(m_device, staging->m_memory, 0, bufferSize, 0, &mappedData));
-
- auto ptr = (unsigned int *)mappedData;
- for (auto i = 0u; i < bufferSize / sizeof(unsigned int); i++)
- fprintf(f, "%X\n", ptr[i]);
-
- vkUnmapMemory(m_device, staging->m_memory);
- }
- else
- {
- printf("invalid output type at %d.\n", id);
- }
- }
- id++;
- }
- fclose(f);
-}
-
void VKRenderer::dispatchCompute(int x, int y, int z)
{
// HACK: create a new pipeline for every call
// First create a pipeline layout based on what is bound
- Slang::List<VkDescriptorSetLayoutBinding> bindings;
+ const auto& srcDetails = m_currentBindingState->m_bindingDetails;
+ const auto& srcBindings = m_currentBindingState->getDesc().m_bindings;
- for (auto bb : m_currentBindingState->m_bindings)
+ const int numBindings = int(srcBindings.Count());
+
+ Slang::List<VkDescriptorSetLayoutBinding> dstBindings;
+ for (int i = 0; i < numBindings; ++i)
{
- switch (bb.type)
+ const auto& srcDetail = srcDetails[i];
+ const auto& srcBinding = srcBindings[i];
+
+ switch (srcBinding.bindingType)
{
- case ShaderInputType::Buffer:
+ case BindingType::Buffer:
{
- switch (bb.bufferType)
+ BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
+ const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc();
+
+ if (bufferResourceDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
{
- case InputBufferType::StorageBuffer:
- {
- VkDescriptorSetLayoutBinding binding = {};
- binding.binding = bb.binding;
- binding.descriptorCount = 1;
- binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- binding.stageFlags = VK_SHADER_STAGE_ALL;
-
- bindings.Add(binding);
- }
- break;
-
- default:
- // handle other cases
- break;
- }
+ VkDescriptorSetLayoutBinding dstBinding = {};
+ dstBinding.binding = srcDetail.m_binding;
+ dstBinding.descriptorCount = 1;
+ dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ dstBinding.stageFlags = VK_SHADER_STAGE_ALL;
+
+ dstBindings.Add(dstBinding);
+ }
+
+ break;
}
- break;
-
default:
// TODO: handle the other cases
break;
@@ -953,8 +915,8 @@ void VKRenderer::dispatchCompute(int x, int y, int z)
}
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
- descriptorSetLayoutInfo.bindingCount = uint32_t(bindings.Count());
- descriptorSetLayoutInfo.pBindings = bindings.Buffer();
+ descriptorSetLayoutInfo.bindingCount = uint32_t(dstBindings.Count());
+ descriptorSetLayoutInfo.pBindings = dstBindings.Buffer();
VkDescriptorSetLayout descriptorSetLayout = 0;
checkResult(vkCreateDescriptorSetLayout(m_device, &descriptorSetLayoutInfo, nullptr, &descriptorSetLayout));
@@ -986,44 +948,44 @@ void VKRenderer::dispatchCompute(int x, int y, int z)
VkDescriptorSet descriptorSet;
checkResult(vkAllocateDescriptorSets(m_device, &descriptorSetAllocInfo, &descriptorSet));
- // Fill in the descritpor set, using our binding information
- for (auto bb : m_currentBindingState->m_bindings)
+ // Fill in the descriptor set, using our binding information
+
+ for (int i = 0; i < numBindings; ++i)
{
- switch (bb.type)
+ const auto& srcDetail = srcDetails[i];
+ const auto& srcBinding = srcBindings[i];
+
+ switch (srcBinding.bindingType)
{
- case ShaderInputType::Buffer:
+ case BindingType::Buffer:
{
- switch (bb.bufferType)
+ BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
+ const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc();
+
+ if (bufferResourceDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
{
- case InputBufferType::StorageBuffer:
- {
- VkDescriptorBufferInfo bufferInfo;
- bufferInfo.buffer = bb.buffer;
- bufferInfo.offset = 0;
- bufferInfo.range = bb.bufferLength;
-
- VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
- writeInfo.descriptorCount = 1;
- writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- writeInfo.dstSet = descriptorSet;
- writeInfo.dstBinding = bb.binding;
- writeInfo.dstArrayElement = 0;
- writeInfo.pBufferInfo = &bufferInfo;
-
- vkUpdateDescriptorSets(m_device, 1, &writeInfo, 0, nullptr);
- }
- break;
-
- default:
- // handle other cases
- break;
+ VkDescriptorBufferInfo bufferInfo;
+ bufferInfo.buffer = bufferResource->m_buffer.m_buffer;
+ bufferInfo.offset = 0;
+ bufferInfo.range = bufferResourceDesc.sizeInBytes;
+
+ VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
+ writeInfo.descriptorCount = 1;
+ writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ writeInfo.dstSet = descriptorSet;
+ writeInfo.dstBinding = srcDetail.m_binding;
+ writeInfo.dstArrayElement = 0;
+ writeInfo.pBufferInfo = &bufferInfo;
+
+ vkUpdateDescriptorSets(m_device, 1, &writeInfo, 0, nullptr);
}
+ break;
}
- break;
-
default:
- // TODO: handle the other cases
+ {
+ // handle other cases
break;
+ }
}
}
diff --git a/tools/render-test/render.cpp b/tools/render-test/render.cpp
index 292aa75f7..3346317e7 100644
--- a/tools/render-test/render.cpp
+++ b/tools/render-test/render.cpp
@@ -21,6 +21,134 @@ using namespace Slang;
BindFlag::Enum(BindFlag::PixelShaderResource | BindFlag::NonPixelShaderResource), // GenericRead
};
+static const Resource::DescBase s_emptyDescBase = {};
+
+const Resource::DescBase& Resource::getDescBase() const
+{
+ if (isBuffer())
+ {
+ return static_cast<const BufferResource *>(this)->getDesc();
+ }
+ else if (isTexture())
+ {
+ return static_cast<const TextureResource *>(this)->getDesc();
+ }
+ return s_emptyDescBase;
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!! BindingState::Desc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+void BindingState::Desc::addSampler(const SamplerDesc& desc, const RegisterDesc& registerDesc)
+{
+ int descIndex = int(m_samplerDescs.Count());
+ m_samplerDescs.Add(desc);
+
+ Binding binding;
+ binding.bindingType = BindingType::Sampler;
+ binding.resource = nullptr;
+ binding.registerDesc = registerDesc;
+ binding.descIndex = descIndex;
+
+ m_bindings.Add(binding);
+}
+
+void BindingState::Desc::addResource(BindingType bindingType, Resource* resource, const RegisterDesc& registerDesc)
+{
+ assert(resource);
+
+ Binding binding;
+ binding.bindingType = bindingType;
+ binding.resource = resource;
+ binding.descIndex = -1;
+ binding.registerDesc = registerDesc;
+ m_bindings.Add(binding);
+}
+
+void BindingState::Desc::addCombinedTextureSampler(TextureResource* resource, const SamplerDesc& samplerDesc, const RegisterDesc& registerDesc)
+{
+ assert(resource);
+
+ int samplerDescIndex = int(m_samplerDescs.Count());
+ m_samplerDescs.Add(samplerDesc);
+
+ Binding binding;
+ binding.bindingType = BindingType::CombinedTextureSampler;
+ binding.resource = resource;
+ binding.descIndex = samplerDescIndex;
+ binding.registerDesc = registerDesc;
+ m_bindings.Add(binding);
+}
+
+BindingState::RegisterSet BindingState::Desc::addRegisterSet(int index)
+{
+ if (index < 0)
+ {
+ return RegisterSet();
+ }
+ return RegisterSet(index, 1);
+}
+
+BindingState::RegisterSet BindingState::Desc::addRegisterSet(const int* srcIndices, int numIndices)
+{
+ assert(numIndices >= 0);
+ switch (numIndices)
+ {
+ case 0: return RegisterSet();
+ case 1: return RegisterSet(srcIndices[0], 1);
+ default:
+ {
+ int startIndex = int(m_indices.Count());
+ m_indices.SetSize(startIndex + numIndices);
+ uint16_t* dstIndices = m_indices.Buffer() + startIndex;
+ for (int i = 0; i < numIndices; i++)
+ {
+ assert(srcIndices[i] >= 0);
+ dstIndices[i] = uint16_t(srcIndices[i]);
+ }
+ return RegisterSet(startIndex, numIndices);
+ }
+ }
+}
+
+int BindingState::Desc::getFirst(const RegisterSet& set) const
+{
+ switch (set.m_numIndices)
+ {
+ case 0: return -1;
+ case 1: return set.m_indexOrBase;
+ default: return m_indices[set.m_indexOrBase];
+ }
+}
+
+int BindingState::Desc::getFirst(ShaderStyle style, const RegisterDesc& registerDesc) const
+{
+ return getFirst(registerDesc.registerSets[int(style)]);
+}
+
+void BindingState::Desc::clear()
+{
+ m_bindings.Clear();
+ m_samplerDescs.Clear();
+ m_indices.Clear();
+ m_numRenderTargets = 1;
+}
+
+BindingState::RegisterList BindingState::Desc::asRegisterList(const RegisterSet& set) const
+{
+ switch (set.m_numIndices)
+ {
+ case 0: return RegisterList{ nullptr, 0 };
+ case 1: return RegisterList{ &set.m_indexOrBase, 1 };
+ default: return RegisterList{ m_indices.Buffer() + set.m_indexOrBase, set.m_numIndices };
+ }
+}
+
+BindingState::RegisterList BindingState::Desc::asRegisterList(ShaderStyle style, const RegisterDesc& registerDesc) const
+{
+ return asRegisterList(registerDesc.registerSets[int(style)]);
+}
+
+
/* !!!!!!!!!!!!!!!!!!!!!!!!!!! TextureResource::Size !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
int TextureResource::Size::calcMaxDimension(Type type) const
diff --git a/tools/render-test/render.h b/tools/render-test/render.h
index 2800e069b..4a25c2369 100644
--- a/tools/render-test/render.h
+++ b/tools/render-test/render.h
@@ -3,13 +3,16 @@
#include "options.h"
#include "window.h"
-#include "shader-input-layout.h"
+
+//#include "shader-input-layout.h"
#include "../../source/core/slang-result.h"
#include "../../source/core/smart-pointer.h"
+#include "../../source/core/list.h"
namespace renderer_test {
+
// Declare opaque type
class InputLayout: public Slang::RefObject
{
@@ -21,10 +24,7 @@ class ShaderProgram: public Slang::RefObject
public:
};
-class BindingState: public Slang::RefObject
-{
- public:
-};
+
struct ShaderCompileRequest
{
@@ -83,6 +83,7 @@ struct InputElementDesc
enum class MapFlavor
{
+ Unknown, ///< Unknown mapping type
HostRead,
HostWrite,
WriteDiscard,
@@ -155,6 +156,13 @@ class Resource: public Slang::RefObject
};
};
+ /// Base class for Descs
+ struct DescBase
+ {
+ int bindFlags = 0; ///< Combination of Resource::BindFlag or 0 (and will use initialUsage to set)
+ int cpuAccessFlags = 0; ///< Combination of Resource::AccessFlag
+ };
+
/// Get the type
SLANG_FORCE_INLINE Type getType() const { return m_type; }
/// True if it's a texture derived type
@@ -162,6 +170,11 @@ class Resource: public Slang::RefObject
/// True if it's a buffer derived type
SLANG_FORCE_INLINE bool isBuffer() const { return m_type == Type::Buffer; }
+ /// Get the descBase
+ const DescBase& getDescBase() const;
+ /// Returns true if can bind with flag
+ bool canBind(BindFlag::Enum bindFlag) const { return (getDescBase().bindFlags & bindFlag) != 0; }
+
/// For a usage gives the required binding flags
static const BindFlag::Enum s_requiredBinding[int(Usage::CountOf)];
@@ -178,21 +191,16 @@ class BufferResource: public Resource
public:
typedef Resource Parent;
- struct Desc
+ struct Desc: public DescBase
{
void init(size_t sizeInBytesIn)
{
- bindFlags = 0;
- cpuAccessFlags = 0;
sizeInBytes = sizeInBytesIn;
elementSize = 0;
}
/// Set up default parameters based on usage
void setDefaults(Usage initialUsage);
- int bindFlags; ///< Combination of Resource::BindFlag or 0 (and will use initialUsage to set)
- int cpuAccessFlags; ///< Combination of Resource::AccessFlag
-
size_t sizeInBytes; ///< Total size in bytes
int elementSize; ///< Get the element stride. If > 0, this is a structured buffer
};
@@ -249,7 +257,7 @@ class TextureResource: public Resource
int depth; ///< Depth (if 3d)
};
- struct Desc
+ struct Desc: public DescBase
{
/// Initialize with default values
void init();
@@ -274,9 +282,6 @@ class TextureResource: public Resource
/// Set up default parameters based on type and usage
void setDefaults(Type type, Usage initialUsage);
- int bindFlags; ///< Combination of Resource::BindFlag or 0 (and will use initialUsage to set)
- int cpuAccessFlags; ///< Combination of Resource::AccessFlag
-
Size size;
int arraySize; ///< Array size
@@ -318,6 +323,124 @@ class TextureResource: public Resource
Desc m_desc;
};
+enum class BindingType
+{
+ Unknown,
+ Sampler,
+ Buffer,
+ Texture,
+ CombinedTextureSampler,
+ CountOf,
+};
+
+class BindingState : public Slang::RefObject
+{
+public:
+
+ enum class ShaderStyle
+ {
+ Hlsl,
+ Glsl,
+ CountOf,
+ };
+
+ struct RegisterSet
+ {
+ /// Default Ctor makes an empty set
+ SLANG_FORCE_INLINE RegisterSet() :
+ m_numIndices(0),
+ m_indexOrBase(0)
+ {}
+ /// Ctor for one or more. NOTE! Meaning if indexIn changes depending if numIndices > 1.
+ SLANG_FORCE_INLINE RegisterSet(int indexIn, int numIndicesIn) :
+ m_numIndices(uint8_t(numIndicesIn)),
+ m_indexOrBase(uint16_t(indexIn))
+ {
+ }
+ uint8_t m_numIndices;
+ uint16_t m_indexOrBase; ///< Meaning changes depending on numIndices. If 1, it is the index if larger than 1, then is an index into 'indices'
+ };
+
+ struct RegisterDesc
+ {
+ RegisterSet registerSets[int(ShaderStyle::CountOf)];
+ };
+
+ struct RegisterList
+ {
+ const uint16_t* begin() const { return indices; }
+ const uint16_t* end() const { return indices + numIndices; }
+
+ int getSize() const { return int(numIndices); }
+ uint16_t operator[](int i) const { assert(i >= 0 && i < numIndices); return indices[i]; }
+
+ const uint16_t* indices;
+ int numIndices;
+ };
+
+ struct SamplerDesc
+ {
+ bool isCompareSampler;
+ };
+
+ struct Binding
+ {
+ BindingType bindingType; ///< Type of binding
+ int descIndex; ///< The description index associated with type. -1 if not used. For example if bindingType is Sampler, the descIndex is into m_samplerDescs.
+ Slang::RefPtr<Resource> resource; ///< Associated resource. nullptr if not used
+ RegisterDesc registerDesc; ///< Registers associated with binding
+ };
+
+ struct Desc
+ {
+ /// Given a RegisterSet, return as a RegisterList, that can be easily iterated over
+ RegisterList asRegisterList(const RegisterSet& set) const;
+ /// Given a RegisterDesc and a style returns a RegisterList, that can be easily iterated over
+ RegisterList asRegisterList(ShaderStyle style, const RegisterDesc& registerDesc) const;
+
+ /// Returns the first member of the set, or returns -1 if is empty
+ int getFirst(const RegisterSet& set) const;
+ /// Returns the first member of the set, or returns -1 if is empty
+ int getFirst(ShaderStyle style, const RegisterDesc& registerDesc) const;
+
+ /// Add a resource - assumed that the binding will match the Desc of the resource
+ void addResource(BindingType bindingType, Resource* resource, const RegisterDesc& registerDesc);
+ /// Add a sampler
+ void addSampler(const SamplerDesc& desc, const RegisterDesc& registerDesc);
+ /// Add a BufferResource
+ void addBufferResource(BufferResource* resource, const RegisterDesc& registerDesc) { addResource(BindingType::Buffer, resource, registerDesc); }
+ /// Add a texture
+ void addTextureResource(TextureResource* resource, const RegisterDesc& registerDesc) { addResource(BindingType::Texture, resource, registerDesc); }
+ /// Add combined texture a
+ void addCombinedTextureSampler(TextureResource* resource, const SamplerDesc& samplerDesc, const RegisterDesc& registerDesc);
+
+ /// Clear the contents
+ void clear();
+
+ /// Given an index, returns as a register set. If index is < 0, assumes means no indices, and just returns the empty set
+ RegisterSet addRegisterSet(int index);
+ /// Given a list of indices, returns the associated register set. Note does check for indices being unique. The order is maintained.
+ /// Only >= 0 indices are valid
+ RegisterSet addRegisterSet(const int* indices, int numIndices);
+
+ Slang::List<Binding> m_bindings;
+ Slang::List<SamplerDesc> m_samplerDescs;
+ Slang::List<uint16_t> m_indices; ///< Used to store lists of registers
+ int m_numRenderTargets = 1;
+ };
+
+ /// Get the Desc used to create this binding
+ SLANG_FORCE_INLINE const Desc& getDesc() const { return m_desc; }
+
+ protected:
+ BindingState(const Desc& desc):
+ m_desc(desc)
+ {
+ }
+
+ Desc m_desc;
+};
+
class Renderer: public Slang::RefObject
{
public:
@@ -334,10 +457,9 @@ public:
virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& desc, const void* initData = nullptr) { return nullptr; }
virtual SlangResult captureScreenShot(const char* outputPath) = 0;
- virtual void serializeOutput(BindingState* state, const char* outputPath) = 0;
virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) = 0;
- virtual BindingState* createBindingState(const ShaderInputLayout& shaderInput) = 0;
+ virtual BindingState* createBindingState(const BindingState::Desc& desc) { return nullptr; }
virtual ShaderCompiler* getShaderCompiler() = 0;
virtual void* map(BufferResource* buffer, MapFlavor flavor) = 0;
diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp
index d45ce55a4..a9079b52c 100644
--- a/tools/render-test/slang-support.cpp
+++ b/tools/render-test/slang-support.cpp
@@ -1,5 +1,7 @@
// slang-support.cpp
+#define _CRT_SECURE_NO_WARNINGS 1
+
#include "slang-support.h"
#include <assert.h>
@@ -291,6 +293,136 @@ SlangResult createInputBufferResource(const InputBufferDesc& inputDesc, bool isO
return SLANG_OK;
}
+static BindingState::SamplerDesc _calcSamplerDesc(const InputSamplerDesc& srcDesc)
+{
+ BindingState::SamplerDesc dstDesc;
+ dstDesc.isCompareSampler = srcDesc.isCompareSampler;
+ return dstDesc;
+}
+
+SlangResult createBindingStateDesc(ShaderInputLayoutEntry* srcEntries, int numEntries, Renderer* renderer, BindingState::Desc& descOut)
+{
+ using namespace Slang;
+
+ const int textureBindFlags = Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource;
+
+ descOut.clear();
+ for (int i = 0; i < numEntries; i++)
+ {
+ const ShaderInputLayoutEntry& srcEntry = srcEntries[i];
+
+ BindingState::RegisterDesc registerDesc;
+ registerDesc.registerSets[int(BindingState::ShaderStyle::Hlsl)] = descOut.addRegisterSet(srcEntry.hlslBinding);
+ registerDesc.registerSets[int(BindingState::ShaderStyle::Glsl)] = descOut.addRegisterSet(srcEntry.glslBinding.Buffer(), int(srcEntry.glslBinding.Count()));
+
+ switch (srcEntry.type)
+ {
+ case ShaderInputType::Buffer:
+ {
+ const InputBufferDesc& srcBuffer = srcEntry.bufferDesc;
+
+ const size_t bufferSize = srcEntry.bufferData.Count() * sizeof(uint32_t);
+
+ RefPtr<BufferResource> bufferResource;
+ SLANG_RETURN_ON_FAIL(createInputBufferResource(srcEntry.bufferDesc, srcEntry.isOutput, bufferSize, srcEntry.bufferData.Buffer(), renderer, bufferResource));
+
+ descOut.addBufferResource(bufferResource, registerDesc);
+ break;
+ }
+ case ShaderInputType::CombinedTextureSampler:
+ {
+ RefPtr<TextureResource> texture;
+ SLANG_RETURN_ON_FAIL(generateTextureResource(srcEntry.textureDesc, textureBindFlags, renderer, texture));
+ descOut.addCombinedTextureSampler(texture, _calcSamplerDesc(srcEntry.samplerDesc), registerDesc);
+ break;
+ }
+ case ShaderInputType::Texture:
+ {
+ RefPtr<TextureResource> texture;
+ SLANG_RETURN_ON_FAIL(generateTextureResource(srcEntry.textureDesc, textureBindFlags, renderer, texture));
+
+ descOut.addTextureResource(texture, registerDesc);
+ break;
+ }
+ case ShaderInputType::Sampler:
+ {
+ descOut.addSampler(_calcSamplerDesc(srcEntry.samplerDesc), registerDesc);
+ break;
+ }
+ default:
+ {
+ assert(!"Unhandled type");
+ return SLANG_FAIL;
+ }
+ }
+ }
+
+ return SLANG_OK;
+}
+
+SlangResult createBindingStateDesc(const ShaderInputLayout& layout, Renderer* renderer, BindingState::Desc& descOut)
+{
+ SLANG_RETURN_ON_FAIL(createBindingStateDesc(layout.entries.Buffer(), int(layout.entries.Count()), renderer, descOut));
+ descOut.m_numRenderTargets = layout.numRenderTargets;
+
+ return SLANG_OK;
+}
+
+SlangResult serializeBindingOutput(const ShaderInputLayout& layout, BindingState* bindingState, Renderer* renderer, const char* fileName)
+{
+ // Submit the work
+ renderer->submitGpuWork();
+ // Wait until everything is complete
+ renderer->waitForGpu();
+
+ FILE * f = fopen(fileName, "wb");
+ if (!f)
+ {
+ return SLANG_FAIL;
+ }
+
+ const BindingState::Desc& bindingStateDesc = bindingState->getDesc();
+ // Must be the same amount of entries
+ assert(bindingStateDesc.m_bindings.Count() == layout.entries.Count());
+
+ const int numBindings = int(bindingStateDesc.m_bindings.Count());
+
+ for (int i = 0; i < numBindings; ++i)
+ {
+ const auto& layoutBinding = layout.entries[i];
+ const auto& binding = bindingStateDesc.m_bindings[i];
+
+ if (layoutBinding.isOutput)
+ {
+ if (binding.resource && binding.resource->isBuffer())
+ {
+ BufferResource* bufferResource = static_cast<BufferResource*>(binding.resource.Ptr());
+ const size_t bufferSize = bufferResource->getDesc().sizeInBytes;
+
+ unsigned int* ptr = (unsigned int*)renderer->map(bufferResource, MapFlavor::HostRead);
+ if (!ptr)
+ {
+ fclose(f);
+ return SLANG_FAIL;
+ }
+
+ const int size = int(bufferSize / sizeof(unsigned int));
+ for (int i = 0; i < size; ++i)
+ {
+ fprintf(f, "%X\n", ptr[i]);
+ }
+ renderer->unmap(bufferResource);
+ }
+ else
+ {
+ printf("invalid output type at %d.\n", i);
+ }
+ }
+ }
+ fclose(f);
+
+ return SLANG_OK;
+}
} // renderer_test
diff --git a/tools/render-test/slang-support.h b/tools/render-test/slang-support.h
index b5b56c295..67d2a2880 100644
--- a/tools/render-test/slang-support.h
+++ b/tools/render-test/slang-support.h
@@ -20,4 +20,12 @@ SlangResult generateTextureResource(const InputTextureDesc& inputDesc, int bindF
/// Create the buffer resource using the renderer
SlangResult createInputBufferResource(const InputBufferDesc& inputDesc, bool isOutput, size_t bufferSize, const void* initData, Renderer* renderer, Slang::RefPtr<BufferResource>& bufferOut);
+SlangResult createBindingStateDesc(ShaderInputLayoutEntry* srcEntries, int numEntries, Renderer* renderer, BindingState::Desc& descOut);
+
+ /// Create binding set from the layout
+SlangResult createBindingStateDesc(const ShaderInputLayout& layout, Renderer* renderer, BindingState::Desc& descOut);
+
+ /// Write out the contents of buffers marked as output in layout to file with 'filename'
+SlangResult serializeBindingOutput(const ShaderInputLayout& layout, BindingState* bindingState, Renderer* renderer, const char* fileName);
+
} // renderer_test