diff options
| -rw-r--r-- | tools/render-test/main.cpp | 20 | ||||
| -rw-r--r-- | tools/render-test/render-d3d11.cpp | 536 | ||||
| -rw-r--r-- | tools/render-test/render-d3d12.cpp | 414 | ||||
| -rw-r--r-- | tools/render-test/render-gl.cpp | 208 | ||||
| -rw-r--r-- | tools/render-test/render-vk.cpp | 554 | ||||
| -rw-r--r-- | tools/render-test/render.cpp | 128 | ||||
| -rw-r--r-- | tools/render-test/render.h | 156 | ||||
| -rw-r--r-- | tools/render-test/slang-support.cpp | 132 | ||||
| -rw-r--r-- | tools/render-test/slang-support.h | 8 |
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 = ⦥ } - 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, ©Info); - - 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, ©Info); + + 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, ©Info); + + 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, ©Info); + + 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, ©Info); - - 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 |
