diff options
Diffstat (limited to 'tools/render-test')
| -rw-r--r-- | tools/render-test/d3d-util.cpp | 11 | ||||
| -rw-r--r-- | tools/render-test/main.cpp | 26 | ||||
| -rw-r--r-- | tools/render-test/render-d3d11.cpp | 536 | ||||
| -rw-r--r-- | tools/render-test/render-d3d12.cpp | 902 | ||||
| -rw-r--r-- | tools/render-test/render-gl.cpp | 554 | ||||
| -rw-r--r-- | tools/render-test/render-test.vcxproj | 1 | ||||
| -rw-r--r-- | tools/render-test/render-test.vcxproj.filters | 3 | ||||
| -rw-r--r-- | tools/render-test/render-vk.cpp | 141 | ||||
| -rw-r--r-- | tools/render-test/render.cpp | 203 | ||||
| -rw-r--r-- | tools/render-test/render.h | 267 | ||||
| -rw-r--r-- | tools/render-test/slang-support.cpp | 120 | ||||
| -rw-r--r-- | tools/render-test/slang-support.h | 8 |
12 files changed, 1931 insertions, 841 deletions
diff --git a/tools/render-test/d3d-util.cpp b/tools/render-test/d3d-util.cpp index 09e0891f9..70ccadddb 100644 --- a/tools/render-test/d3d-util.cpp +++ b/tools/render-test/d3d-util.cpp @@ -26,12 +26,11 @@ using namespace Slang; { switch (format) { - case Format::RGB_Float32: - return DXGI_FORMAT_R32G32B32_FLOAT; - case Format::RG_Float32: - return DXGI_FORMAT_R32G32_FLOAT; - default: - return DXGI_FORMAT_UNKNOWN; + case Format::RGB_Float32: return DXGI_FORMAT_R32G32B32_FLOAT; + case Format::RG_Float32: return DXGI_FORMAT_R32G32_FLOAT; + case Format::R_Float32: return DXGI_FORMAT_R32_FLOAT; + case Format::RGBA_Unorm_UInt8: return DXGI_FORMAT_R8G8B8A8_UNORM; + default: return DXGI_FORMAT_UNKNOWN; } } diff --git a/tools/render-test/main.cpp b/tools/render-test/main.cpp index 12160ae78..acc7ffb78 100644 --- a/tools/render-test/main.cpp +++ b/tools/render-test/main.cpp @@ -73,11 +73,11 @@ class RenderTestApp RefPtr<Renderer> m_renderer; - RefPtr<Buffer> m_constantBuffer; - RefPtr<InputLayout> m_inputLayout; - RefPtr<Buffer> m_vertexBuffer; - RefPtr<ShaderProgram> m_shaderProgram; - RefPtr<BindingState> m_bindingState; + RefPtr<BufferResource> m_constantBuffer; + RefPtr<InputLayout> m_inputLayout; + RefPtr<BufferResource> m_vertexBuffer; + RefPtr<ShaderProgram> m_shaderProgram; + RefPtr<BindingState> m_bindingState; ShaderInputLayout m_shaderInputLayout; }; @@ -106,11 +106,11 @@ SlangResult RenderTestApp::initialize(Renderer* renderer, ShaderCompiler* shader // TODO(tfoley): use each API's reflection interface to query the constant-buffer size needed m_constantBufferSize = 16 * sizeof(float); - BufferDesc constantBufferDesc; - constantBufferDesc.size = m_constantBufferSize; - constantBufferDesc.flavor = BufferFlavor::Constant; + BufferResource::Desc constantBufferDesc; + constantBufferDesc.init(m_constantBufferSize); + constantBufferDesc.cpuAccessFlags = Resource::AccessFlag::Write; - m_constantBuffer = renderer->createBuffer(constantBufferDesc); + m_constantBuffer = renderer->createBufferResource(Resource::Usage::ConstantBuffer, constantBufferDesc); if(!m_constantBuffer) return SLANG_FAIL; @@ -126,12 +126,10 @@ SlangResult RenderTestApp::initialize(Renderer* renderer, ShaderCompiler* shader if(!m_inputLayout) return SLANG_FAIL; - BufferDesc vertexBufferDesc; - vertexBufferDesc.size = kVertexCount * sizeof(Vertex); - vertexBufferDesc.flavor = BufferFlavor::Vertex; - vertexBufferDesc.initData = &kVertexData[0]; + BufferResource::Desc vertexBufferDesc; + vertexBufferDesc.init(kVertexCount * sizeof(Vertex)); - m_vertexBuffer = renderer->createBuffer(vertexBufferDesc); + m_vertexBuffer = renderer->createBufferResource(Resource::Usage::VertexBuffer, vertexBufferDesc, kVertexData); if(!m_vertexBuffer) return SLANG_FAIL; diff --git a/tools/render-test/render-d3d11.cpp b/tools/render-test/render-d3d11.cpp index e65b12b2c..18e41db7e 100644 --- a/tools/render-test/render-d3d11.cpp +++ b/tools/render-test/render-d3d11.cpp @@ -9,6 +9,8 @@ #include <slang.h> +#include "slang-support.h" + #include "../../source/core/slang-com-ptr.h" #ifdef _MSC_VER @@ -51,20 +53,21 @@ public: virtual void setClearColor(const float color[4]) override; virtual void clearFrame() override; virtual void presentFrame() override; + 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 Buffer* createBuffer(const BufferDesc& desc) override; virtual InputLayout* createInputLayout( const InputElementDesc* inputElements, UInt inputElementCount) override; virtual BindingState * createBindingState(const ShaderInputLayout& layout) override; virtual ShaderCompiler* getShaderCompiler() override; - virtual void* map(Buffer* buffer, MapFlavor flavor) override; - virtual void unmap(Buffer* buffer) override; + virtual void* map(BufferResource* buffer, MapFlavor flavor) override; + virtual void unmap(BufferResource* buffer) override; virtual void setInputLayout(InputLayout* inputLayout) override; virtual void setPrimitiveTopology(PrimitiveTopology topology) override; virtual void setBindingState(BindingState * state); - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* strides, const UInt* offsets) override; + virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override; virtual void setShaderProgram(ShaderProgram* inProgram) override; - virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* offsets) override; + virtual void setConstantBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets) override; virtual void draw(UInt vertexCount, UInt startVertex) override; virtual void dispatchCompute(int x, int y, int z) override; virtual void submitGpuWork() override {} @@ -79,13 +82,15 @@ public: { ShaderInputType type; InputBufferType bufferType; // Only valid if `type` is `Buffer` + ComPtr<ID3D11ShaderResourceView> srv; ComPtr<ID3D11UnorderedAccessView> uav; - ComPtr<ID3D11Buffer> buffer; ComPtr<ID3D11SamplerState> samplerState; + + RefPtr<Resource> resource; /// Can hold texture of buffer + int binding = 0; bool isOutput = false; - int bufferLength = 0; }; class BindingStateImpl: public BindingState @@ -102,10 +107,34 @@ public: ComPtr<ID3D11ComputeShader> m_computeShader; }; - class BufferImpl: public Buffer + class BufferResourceImpl: public BufferResource { public: + typedef BufferResource Parent; + + BufferResourceImpl(const Desc& desc, Usage initialUsage): + Parent(desc), + m_initialUsage(initialUsage) + { + } + + MapFlavor m_mapFlavor; + Usage m_initialUsage; ComPtr<ID3D11Buffer> m_buffer; + ComPtr<ID3D11Buffer> m_staging; + }; + class TextureResourceImpl : public TextureResource + { + public: + typedef TextureResource Parent; + + TextureResourceImpl(Type type, const Desc& desc, Usage initialUsage) : + Parent(type, desc), + m_initialUsage(initialUsage) + { + } + Usage m_initialUsage; + ComPtr<ID3D11Resource> m_resource; }; class InputLayoutImpl: public InputLayout @@ -117,13 +146,13 @@ 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); + //void* map(ID3D11Buffer* buffer, MapFlavor flavor); + //void unmap(ID3D11Buffer* buffer); - Result createInputBuffer(const InputBufferDesc& bufferDesc, const List<unsigned int>& bufferData, - ComPtr<ID3D11Buffer>& bufferOut, ComPtr<ID3D11UnorderedAccessView>& viewOut, ComPtr<ID3D11ShaderResourceView>& srvOut); + 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, ComPtr<ID3D11ShaderResourceView>& viewOut); + Result createInputTexture(const InputTextureDesc& inputDesc, RefPtr<Resource>& resourceOut, ComPtr<ID3D11ShaderResourceView>& viewOut); Result createInputSampler(const InputSamplerDesc& inputDesc, ComPtr<ID3D11SamplerState>& stateOut); @@ -387,37 +416,242 @@ ShaderCompiler* D3D11Renderer::getShaderCompiler() return this; } -Buffer* D3D11Renderer::createBuffer(const BufferDesc& desc) +static D3D11_BIND_FLAG _calcResourceFlag(Resource::BindFlag::Enum bindFlag) { - D3D11_BUFFER_DESC bufferDesc = { 0 }; - bufferDesc.ByteWidth = (UINT)D3DUtil::calcAligned(desc.size, 256); + typedef Resource::BindFlag BindFlag; + switch (bindFlag) + { + case BindFlag::VertexBuffer: return D3D11_BIND_VERTEX_BUFFER; + case BindFlag::IndexBuffer: return D3D11_BIND_INDEX_BUFFER; + case BindFlag::ConstantBuffer: return D3D11_BIND_CONSTANT_BUFFER; + case BindFlag::StreamOutput: return D3D11_BIND_STREAM_OUTPUT; + case BindFlag::RenderTarget: return D3D11_BIND_RENDER_TARGET; + case BindFlag::DepthStencil: return D3D11_BIND_DEPTH_STENCIL; + case BindFlag::UnorderedAccess: return D3D11_BIND_UNORDERED_ACCESS; + case BindFlag::PixelShaderResource: return D3D11_BIND_SHADER_RESOURCE; + case BindFlag::NonPixelShaderResource: return D3D11_BIND_SHADER_RESOURCE; + default: return D3D11_BIND_FLAG(0); + } +} + +static int _calcResourceBindFlags(int bindFlags) +{ + int dstFlags = 0; + while (bindFlags) + { + int lsb = bindFlags & -bindFlags; + + dstFlags |= _calcResourceFlag(Resource::BindFlag::Enum(lsb)); + bindFlags &= ~lsb; + } + return dstFlags; +} - switch (desc.flavor) +static int _calcResourceAccessFlags(int accessFlags) +{ + switch (accessFlags) { - case BufferFlavor::Constant: - bufferDesc.Usage = D3D11_USAGE_DYNAMIC; - bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + case 0: return 0; + case Resource::AccessFlag::Read: return D3D11_CPU_ACCESS_READ; + case Resource::AccessFlag::Write: return D3D11_CPU_ACCESS_WRITE; + case Resource::AccessFlag::Read | + Resource::AccessFlag::Write: return D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + default: assert(!"Invalid flags"); return 0; + } +} + +TextureResource* D3D11Renderer::createTextureResource(Resource::Type type, Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData) +{ + TextureResource::Desc srcDesc(descIn); + srcDesc.setDefaults(type, initialUsage); + + const int effectiveArraySize = srcDesc.calcEffectiveArraySize(type); + + assert(initData); + assert(initData->numSubResources == srcDesc.numMipLevels * effectiveArraySize * srcDesc.size.depth); + + const DXGI_FORMAT format = D3DUtil::getMapFormat(srcDesc.format); + if (format == DXGI_FORMAT_UNKNOWN) + { + return nullptr; + } + + const int bindFlags = _calcResourceBindFlags(srcDesc.bindFlags); + + // Set up the initialize data + List<D3D11_SUBRESOURCE_DATA> subRes; + subRes.SetSize(srcDesc.numMipLevels * effectiveArraySize); + { + int subResourceIndex = 0; + for (int i = 0; i < effectiveArraySize; i++) + { + for (int j = 0; j < srcDesc.numMipLevels; j++) + { + const int mipHeight = TextureResource::calcMipSize(srcDesc.size.height, j); + + D3D11_SUBRESOURCE_DATA& data = subRes[subResourceIndex]; + + data.pSysMem = initData->subResources[subResourceIndex]; + + data.SysMemPitch = UINT(initData->mipRowStrides[j]); + data.SysMemSlicePitch = UINT(initData->mipRowStrides[j] * mipHeight); + + subResourceIndex++; + } + } + } + + const int accessFlags = _calcResourceAccessFlags(srcDesc.cpuAccessFlags); + + RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(type, srcDesc, initialUsage)); + + switch (type) + { + case Resource::Type::Texture1D: + { + D3D11_TEXTURE1D_DESC desc = { 0 }; + desc.BindFlags = bindFlags; + desc.CPUAccessFlags = accessFlags; + desc.Format = format; + desc.MiscFlags = 0; + desc.MipLevels = srcDesc.numMipLevels; + desc.ArraySize = effectiveArraySize; + desc.Width = srcDesc.size.width; + desc.Usage = D3D11_USAGE_DEFAULT; + + ComPtr<ID3D11Texture1D> texture1D; + SLANG_RETURN_NULL_ON_FAIL(m_device->CreateTexture1D(&desc, subRes.Buffer(), texture1D.writeRef())); + + texture->m_resource = texture1D; break; + } + case Resource::Type::TextureCube: + case Resource::Type::Texture2D: + { + D3D11_TEXTURE2D_DESC desc = { 0 }; + desc.BindFlags = bindFlags; + desc.CPUAccessFlags = accessFlags; + desc.Format = format; + desc.MiscFlags = 0; + desc.MipLevels = srcDesc.numMipLevels; + desc.ArraySize = effectiveArraySize; + + desc.Width = srcDesc.size.width; + desc.Height = srcDesc.size.height; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.SampleDesc.Count = srcDesc.sampleDesc.numSamples; + desc.SampleDesc.Quality = srcDesc.sampleDesc.quality; + + if (type == Resource::Type::TextureCube) + { + desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; + } + + ComPtr<ID3D11Texture2D> texture2D; + SLANG_RETURN_NULL_ON_FAIL(m_device->CreateTexture2D(&desc, subRes.Buffer(), texture2D.writeRef())); + + texture->m_resource = texture2D; + break; + } + case Resource::Type::Texture3D: + { + D3D11_TEXTURE3D_DESC desc = { 0 }; + desc.BindFlags = bindFlags; + desc.CPUAccessFlags = accessFlags; + desc.Format = format; + desc.MiscFlags = 0; + desc.MipLevels = srcDesc.numMipLevels; + desc.Width = srcDesc.size.width; + desc.Height = srcDesc.size.height; + desc.Depth = srcDesc.size.depth; + desc.Usage = D3D11_USAGE_DEFAULT; + + ComPtr<ID3D11Texture3D> texture3D; + SLANG_RETURN_NULL_ON_FAIL(m_device->CreateTexture3D(&desc, subRes.Buffer(), texture3D.writeRef())); + + texture->m_resource = texture3D; + break; + } + default: return nullptr; + } + + return texture.detach(); +} + +BufferResource* D3D11Renderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData) +{ + BufferResource::Desc srcDesc(descIn); + srcDesc.setDefaults(initialUsage); + + // Make aligned to 256 bytes... not sure why, but if you remove this the tests do fail. + const size_t alignedSizeInBytes = D3DUtil::calcAligned(srcDesc.sizeInBytes, 256); + + // Hack to make the initialization never read from out of bounds memory, by copying into a buffer + List<uint8_t> initDataBuffer; + if (initData && alignedSizeInBytes > srcDesc.sizeInBytes) + { + initDataBuffer.SetSize(alignedSizeInBytes); + ::memcpy(initDataBuffer.Buffer(), initData, srcDesc.sizeInBytes); + initData = initDataBuffer.Buffer(); + } + + D3D11_BUFFER_DESC bufferDesc = { 0 }; + bufferDesc.ByteWidth = UINT(alignedSizeInBytes); + bufferDesc.BindFlags = _calcResourceBindFlags(srcDesc.bindFlags); + // For read we'll need to do some staging + bufferDesc.CPUAccessFlags = _calcResourceAccessFlags(descIn.cpuAccessFlags & Resource::AccessFlag::Write); + bufferDesc.Usage = D3D11_USAGE_DEFAULT; + + // If written by CPU, make it dynamic + if (descIn.cpuAccessFlags & Resource::AccessFlag::Write) + { + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + } - case BufferFlavor::Vertex: + switch (initialUsage) + { + case Resource::Usage::ConstantBuffer: + { + // We'll just assume ConstantBuffers are dynamic for now bufferDesc.Usage = D3D11_USAGE_DYNAMIC; - bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; break; - default: - return nullptr; + } + default: break; + } + + if (bufferDesc.BindFlags & (D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE)) + { + //desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; + if (srcDesc.elementSize != 0) + { + bufferDesc.StructureByteStride = srcDesc.elementSize; + bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + } + else + { + bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; + } } D3D11_SUBRESOURCE_DATA subResourceData = { 0 }; - subResourceData.pSysMem = desc.initData; + subResourceData.pSysMem = initData; - ComPtr<ID3D11Buffer> buffer; - SLANG_RETURN_NULL_ON_FAIL(m_device->CreateBuffer(&bufferDesc, desc.initData ? &subResourceData : nullptr, buffer.writeRef())); + RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(srcDesc, initialUsage)); + + SLANG_RETURN_NULL_ON_FAIL(m_device->CreateBuffer(&bufferDesc, initData ? &subResourceData : nullptr, buffer->m_buffer.writeRef())); - BufferImpl* rs = new BufferImpl; - rs->m_buffer = buffer; - return rs; + if (srcDesc.cpuAccessFlags & Resource::AccessFlag::Read) + { + D3D11_BUFFER_DESC bufDesc = {}; + bufDesc.BindFlags = 0; + bufDesc.ByteWidth = (UINT)alignedSizeInBytes; + bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + bufDesc.Usage = D3D11_USAGE_STAGING; + + SLANG_RETURN_NULL_ON_FAIL(m_device->CreateBuffer(&bufDesc, nullptr, buffer->m_staging.writeRef())); + } + + return buffer.detach(); } InputLayout* D3D11Renderer::createInputLayout(const InputElementDesc* inputElementsIn, UInt inputElementCount) @@ -453,6 +687,9 @@ InputLayout* D3D11Renderer::createInputLayout(const InputElementDesc* inputEleme case Format::RG_Float32: typeName = "float2"; break; + case Format::R_Float32: + typeName = "float"; + break; default: return nullptr; } @@ -479,10 +716,14 @@ InputLayout* D3D11Renderer::createInputLayout(const InputElementDesc* inputEleme return impl; } -void* D3D11Renderer::map(ID3D11Buffer* buffer, MapFlavor flavorIn) +void* D3D11Renderer::map(BufferResource* bufferIn, MapFlavor flavor) { + BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(bufferIn); + D3D11_MAP mapType; - switch (flavorIn) + ID3D11Buffer* buffer = bufferResource->m_buffer; + + switch (flavor) { case MapFlavor::WriteDiscard: mapType = D3D11_MAP_WRITE_DISCARD; @@ -492,6 +733,16 @@ void* D3D11Renderer::map(ID3D11Buffer* buffer, MapFlavor flavorIn) break; case MapFlavor::HostRead: mapType = D3D11_MAP_READ; + + buffer = bufferResource->m_staging; + if (!buffer) + { + return nullptr; + } + + // Okay copy the data over + m_immediateContext->CopyResource(buffer, bufferResource->m_buffer); + break; default: return nullptr; @@ -502,23 +753,17 @@ void* D3D11Renderer::map(ID3D11Buffer* buffer, MapFlavor flavorIn) // per-frame (we always use an identity projection). D3D11_MAPPED_SUBRESOURCE mappedSub; SLANG_RETURN_NULL_ON_FAIL(m_immediateContext->Map(buffer, 0, mapType, 0, &mappedSub)); - - return mappedSub.pData; -} -void* D3D11Renderer::map(Buffer* buffer, MapFlavor flavor) -{ - return map(((BufferImpl*)buffer)->m_buffer, flavor); -} + bufferResource->m_mapFlavor = flavor; -void D3D11Renderer::unmap(ID3D11Buffer* buffer) -{ - m_immediateContext->Unmap(buffer, 0); + return mappedSub.pData; } -void D3D11Renderer::unmap(Buffer* bufferIn) +void D3D11Renderer::unmap(BufferResource* bufferIn) { - unmap(((BufferImpl*)bufferIn)->m_buffer); + BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(bufferIn); + ID3D11Buffer* buffer = (bufferResource->m_mapFlavor == MapFlavor::HostRead) ? bufferResource->m_staging : bufferResource->m_buffer; + m_immediateContext->Unmap(buffer, 0); } void D3D11Renderer::setInputLayout(InputLayout* inputLayoutIn) @@ -532,7 +777,7 @@ void D3D11Renderer::setPrimitiveTopology(PrimitiveTopology topology) m_immediateContext->IASetPrimitiveTopology(D3DUtil::getPrimitiveTopology(topology)); } -void D3D11Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffersIn, const UInt* stridesIn, const UInt* offsetsIn) +void D3D11Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffersIn, const UInt* stridesIn, const UInt* offsetsIn) { static const int kMaxVertexBuffers = 16; assert(slotCount <= kMaxVertexBuffers); @@ -541,7 +786,7 @@ void D3D11Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, Buffer*cons UINT vertexOffsets[kMaxVertexBuffers]; ID3D11Buffer* dxBuffers[kMaxVertexBuffers]; - auto buffers = (BufferImpl*const*)buffersIn; + auto buffers = (BufferResourceImpl*const*)buffersIn; for (UInt ii = 0; ii < slotCount; ++ii) { @@ -561,14 +806,14 @@ void D3D11Renderer::setShaderProgram(ShaderProgram* programIn) m_immediateContext->PSSetShader(program->m_pixelShader, nullptr, 0); } -void D3D11Renderer::setConstantBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffersIn, const UInt* offsetsIn) +void D3D11Renderer::setConstantBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffersIn, const UInt* offsetsIn) { static const int kMaxConstantBuffers = 16; assert(slotCount <= kMaxConstantBuffers); // TODO: actually use those offsets - auto buffers = (BufferImpl*const*)buffersIn; + auto buffers = (BufferResourceImpl*const*)buffersIn; // Copy out the actual dx buffers ID3D11Buffer* dxBuffers[kMaxConstantBuffers]; @@ -626,38 +871,16 @@ void D3D11Renderer::dispatchCompute(int x, int y, int z) m_immediateContext->Dispatch(x, y, z); } -Result D3D11Renderer::createInputBuffer(const InputBufferDesc& bufferDesc, const List<unsigned int>& bufferData, - ComPtr<ID3D11Buffer>& bufferOut, ComPtr<ID3D11UnorderedAccessView>& viewOut, ComPtr<ID3D11ShaderResourceView>& srvOut) +Result D3D11Renderer::createInputBuffer(const InputBufferDesc& bufferDesc, bool isOutput, const List<unsigned int>& bufferData, + RefPtr<Resource>& resourceOut, ComPtr<ID3D11UnorderedAccessView>& viewOut, ComPtr<ID3D11ShaderResourceView>& srvOut) { - D3D11_BUFFER_DESC desc = { 0 }; - List<unsigned int> newBuffer; - desc.ByteWidth = (UINT)D3DUtil::calcAligned((bufferData.Count() * sizeof(unsigned int)), 256); - newBuffer.SetSize(desc.ByteWidth / sizeof(unsigned int)); - for (UInt i = 0; i < bufferData.Count(); i++) - newBuffer[i] = bufferData[i]; - if (bufferDesc.type == InputBufferType::ConstantBuffer) - { - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - } - else - { - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; - if (bufferDesc.stride != 0) - { - desc.StructureByteStride = bufferDesc.stride; - desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; - } - else - { - desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; - } - } - D3D11_SUBRESOURCE_DATA data = { 0 }; - data.pSysMem = newBuffer.Buffer(); - SLANG_RETURN_ON_FAIL(m_device->CreateBuffer(&desc, &data, bufferOut.writeRef())); - int elemSize = bufferDesc.stride <= 0 ? 1 : bufferDesc.stride; + 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; @@ -677,7 +900,7 @@ Result D3D11Renderer::createInputBuffer(const InputBufferDesc& bufferDesc, const viewDesc.Format = DXGI_FORMAT_R32_TYPELESS; } - SLANG_RETURN_ON_FAIL(m_device->CreateUnorderedAccessView(bufferOut, &viewDesc, viewOut.writeRef())); + SLANG_RETURN_ON_FAIL(m_device->CreateUnorderedAccessView(bufferImpl->m_buffer, &viewDesc, viewOut.writeRef())); } if (bufferDesc.type != InputBufferType::ConstantBuffer) { @@ -695,78 +918,55 @@ Result D3D11Renderer::createInputBuffer(const InputBufferDesc& bufferDesc, const srvDesc.Format = DXGI_FORMAT_R32_FLOAT; } - SLANG_RETURN_ON_FAIL(m_device->CreateShaderResourceView(bufferOut, &srvDesc, srvOut.writeRef())); + SLANG_RETURN_ON_FAIL(m_device->CreateShaderResourceView(bufferImpl->m_buffer, &srvDesc, srvOut.writeRef())); } + resourceOut = bufferResource; + return SLANG_OK; } -Result D3D11Renderer::createInputTexture(const InputTextureDesc& inputDesc, ComPtr<ID3D11ShaderResourceView>& viewOut) +Result D3D11Renderer::createInputTexture(const InputTextureDesc& inputDesc, RefPtr<Resource>& resourceOut, ComPtr<ID3D11ShaderResourceView>& viewOut) { ComPtr<ID3D11ShaderResourceView> view; - TextureData texData; - generateTextureData(texData, inputDesc); - List<D3D11_SUBRESOURCE_DATA> subRes; - for (int i = 0; i < texData.arraySize; i++) - { - int slice = 0; - for (int j = 0; j < texData.mipLevels; j++) - { - int size = texData.textureSize >> j; - D3D11_SUBRESOURCE_DATA res; - res.pSysMem = texData.dataBuffer[slice].Buffer(); - res.SysMemPitch = sizeof(unsigned int) * size; - res.SysMemSlicePitch = sizeof(unsigned int) * size * size; - subRes.Add(res); - slice++; - } - } - if (inputDesc.dimension == 1) - { - D3D11_TEXTURE1D_DESC desc = { 0 }; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = 0; - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - desc.MiscFlags = 0; - desc.MipLevels = texData.mipLevels; - desc.ArraySize = texData.arraySize; - desc.Width = texData.textureSize; - desc.Usage = D3D11_USAGE_DEFAULT; + int bindFlags = 0; + + RefPtr<TextureResource> texture; + SLANG_RETURN_ON_FAIL(generateTextureResource(inputDesc, bindFlags, this, texture)); - ComPtr<ID3D11Texture1D> texture; - SLANG_RETURN_ON_FAIL(m_device->CreateTexture1D(&desc, subRes.Buffer(), texture.writeRef())); + //DXGI_FORMAT format = textureImpl->m_resource->GetD + const TextureResource::Desc& textureDesc = texture->getDesc(); + DXGI_FORMAT format = D3DUtil::getMapFormat(textureDesc.format); + + TextureResourceImpl* textureImpl = static_cast<TextureResourceImpl*>(texture.Ptr()); + + 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 = texData.mipLevels; + viewDesc.Texture1D.MipLevels = textureDesc.numMipLevels; viewDesc.Texture1D.MostDetailedMip = 0; - viewDesc.Texture1DArray.ArraySize = texData.arraySize; + viewDesc.Texture1DArray.ArraySize = textureDesc.arraySize; viewDesc.Texture1DArray.FirstArraySlice = 0; - viewDesc.Texture1DArray.MipLevels = texData.mipLevels; + viewDesc.Texture1DArray.MipLevels = textureDesc.numMipLevels; viewDesc.Texture1DArray.MostDetailedMip = 0; - viewDesc.Format = desc.Format; - m_device->CreateShaderResourceView(texture, &viewDesc, view.writeRef()); + viewDesc.Format = format; + m_device->CreateShaderResourceView(textureImpl->m_resource, &viewDesc, view.writeRef()); } else if (inputDesc.dimension == 2) { D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; - D3D11_TEXTURE2D_DESC desc = { 0 }; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = 0; - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - desc.MiscFlags = 0; - desc.MipLevels = texData.mipLevels; - desc.ArraySize = texData.arraySize; + if (inputDesc.isCube) { - desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; - viewDesc.TextureCube.MipLevels = texData.mipLevels; + viewDesc.TextureCube.MipLevels = textureDesc.numMipLevels; viewDesc.TextureCube.MostDetailedMip = 0; - viewDesc.TextureCubeArray.MipLevels = texData.mipLevels; + viewDesc.TextureCubeArray.MipLevels = textureDesc.numMipLevels; viewDesc.TextureCubeArray.MostDetailedMip = 0; viewDesc.TextureCubeArray.First2DArrayFace = 0; viewDesc.TextureCubeArray.NumCubes = inputDesc.arrayLength; @@ -774,49 +974,31 @@ Result D3D11Renderer::createInputTexture(const InputTextureDesc& inputDesc, ComP else { viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - viewDesc.Texture2D.MipLevels = texData.mipLevels; + viewDesc.Texture2D.MipLevels = textureDesc.numMipLevels; viewDesc.Texture2D.MostDetailedMip = 0; - viewDesc.Texture2DArray.ArraySize = texData.arraySize; + viewDesc.Texture2DArray.ArraySize = textureDesc.arraySize; viewDesc.Texture2DArray.FirstArraySlice = 0; - viewDesc.Texture2DArray.MipLevels = texData.mipLevels; + viewDesc.Texture2DArray.MipLevels = textureDesc.numMipLevels; viewDesc.Texture2DArray.MostDetailedMip = 0; } if (inputDesc.arrayLength != 0) viewDesc.ViewDimension = (D3D11_SRV_DIMENSION)(int)(viewDesc.ViewDimension + 1); - desc.Width = texData.textureSize; - desc.Height = texData.textureSize; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - viewDesc.Format = desc.Format; - ComPtr<ID3D11Texture2D> texture; - SLANG_RETURN_ON_FAIL(m_device->CreateTexture2D(&desc, subRes.Buffer(), texture.writeRef())); - SLANG_RETURN_ON_FAIL(m_device->CreateShaderResourceView(texture, &viewDesc, view.writeRef())); + 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; - D3D11_TEXTURE3D_DESC desc = { 0 }; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = 0; - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - desc.MiscFlags = 0; - desc.MipLevels = 1; viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; - desc.Width = texData.textureSize; - desc.Height = texData.textureSize; - desc.Depth = texData.textureSize; - desc.Usage = D3D11_USAGE_DEFAULT; - - ComPtr<ID3D11Texture3D> texture; - m_device->CreateTexture3D(&desc, subRes.Buffer(), texture.writeRef()); - viewDesc.Texture3D.MipLevels = 1; + viewDesc.Texture3D.MipLevels = 1; viewDesc.Texture3D.MostDetailedMip = 0; - viewDesc.Format = desc.Format; - m_device->CreateShaderResourceView(texture, &viewDesc, view.writeRef()); + viewDesc.Format = format; + m_device->CreateShaderResourceView(textureImpl->m_resource, &viewDesc, view.writeRef()); } + resourceOut = texture; viewOut.swap(view); return SLANG_OK; } @@ -866,15 +1048,13 @@ BindingState* D3D11Renderer::createBindingState(const ShaderInputLayout& layout) { case ShaderInputType::Buffer: { - SLANG_RETURN_NULL_ON_FAIL(createInputBuffer(srcBinding.bufferDesc, srcBinding.bufferData, dstBinding.buffer, dstBinding.uav, dstBinding.srv)); - - dstBinding.bufferLength = (int)(srcBinding.bufferData.Count() * sizeof(unsigned int)); + 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.srv)); + SLANG_RETURN_NULL_ON_FAIL(createInputTexture(srcBinding.textureDesc, dstBinding.resource, dstBinding.srv)); break; } case ShaderInputType::Sampler: @@ -902,14 +1082,18 @@ void D3D11Renderer::applyBindingState(bool isCompute) { 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, binding.buffer.readRef()); + context->CSSetConstantBuffers(binding.binding, 1, &buffer); else { - context->VSSetConstantBuffers(binding.binding, 1, binding.buffer.readRef()); - context->PSSetConstantBuffers(binding.binding, 1, binding.buffer.readRef()); + context->VSSetConstantBuffers(binding.binding, 1, &buffer); + context->PSSetConstantBuffers(binding.binding, 1, &buffer); } } else if (binding.uav) @@ -981,25 +1165,17 @@ void D3D11Renderer::serializeOutput(BindingState* stateIn, const char* fileName) { if (binding.isOutput) { - if (binding.buffer) + if (binding.resource && binding.resource->isBuffer()) { - // create staging buffer - ComPtr<ID3D11Buffer> stageBuf; - - D3D11_BUFFER_DESC bufDesc; - memset(&bufDesc, 0, sizeof(bufDesc)); - bufDesc.BindFlags = 0; - bufDesc.ByteWidth = (UINT)D3DUtil::calcAligned(binding.bufferLength, 256); - bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - bufDesc.Usage = D3D11_USAGE_STAGING; + BufferResource* bufferResource = static_cast<BufferResource*>(binding.resource.Ptr()); + const size_t bufferSize = bufferResource->getDesc().sizeInBytes; - SLANG_RETURN_VOID_ON_FAIL(m_device->CreateBuffer(&bufDesc, nullptr, stageBuf.writeRef())); - m_immediateContext->CopyResource(stageBuf, binding.buffer); - - auto ptr = (unsigned int *)map(stageBuf, MapFlavor::HostRead); - for (auto i = 0u; i < binding.bufferLength / sizeof(unsigned int); i++) + 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(stageBuf); + } + unmap(bufferResource); } else { diff --git a/tools/render-test/render-d3d12.cpp b/tools/render-test/render-d3d12.cpp index 9d4fdf03c..2d024396a 100644 --- a/tools/render-test/render-d3d12.cpp +++ b/tools/render-test/render-d3d12.cpp @@ -3,6 +3,7 @@ #include "options.h" #include "render.h" +#include "slang-support.h" // In order to use the Slang API, we need to include its header @@ -60,20 +61,21 @@ public: virtual void setClearColor(const float color[4]) override; virtual void clearFrame() override; virtual void presentFrame() override; + 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 Buffer* createBuffer(const BufferDesc& desc) override; virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override; virtual BindingState* createBindingState(const ShaderInputLayout& layout) override; virtual ShaderCompiler* getShaderCompiler() override; - virtual void* map(Buffer* buffer, MapFlavor flavor) override; - virtual void unmap(Buffer* buffer) override; + virtual void* map(BufferResource* buffer, MapFlavor flavor) override; + virtual void unmap(BufferResource* buffer) override; virtual void setInputLayout(InputLayout* inputLayout) override; virtual void setPrimitiveTopology(PrimitiveTopology topology) override; virtual void setBindingState(BindingState* state); - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* strides, const UInt* offsets) override; + virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override; virtual void setShaderProgram(ShaderProgram* inProgram) override; - virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* offsets) override; + virtual void setConstantBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets) override; virtual void draw(UInt vertexCount, UInt startVertex) override; virtual void dispatchCompute(int x, int y, int z) override; virtual void submitGpuWork() override; @@ -90,8 +92,15 @@ protected: enum class ProgramType { - kCompute, - kGraphics, + Compute, + Graphics, + }; + + struct Submitter + { + virtual void setRootConstantBufferView(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) = 0; + virtual void setRootDescriptorTable(int index, D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor) = 0; + virtual void setRootSignature(ID3D12RootSignature* rootSignature) = 0; }; struct FrameInfo @@ -113,22 +122,81 @@ protected: List<uint8_t> m_pixelShader; List<uint8_t> m_computeShader; }; - class BufferImpl: public Buffer + + class BufferResourceImpl: public BufferResource { public: - BufferImpl(const BufferDesc& desc): - m_desc(desc), - m_mapFlavor(MapFlavor::HostRead) + typedef BufferResource Parent; + + enum class BackingStyle { + Unknown, + ResourceBacked, ///< The contents is only held within the resource + MemoryBacked, ///< The current contents is held in m_memory and copied to GPU every time it's used (typically used for constant buffers) + }; + + void bindConstantBufferView(D3D12CircularResourceHeap& circularHeap, int index, Submitter* submitter) const + { + switch (m_backingStyle) + { + case BackingStyle::MemoryBacked: + { + const size_t bufferSize = m_memory.Count(); + D3D12CircularResourceHeap::Cursor cursor = circularHeap.allocateConstantBuffer(bufferSize); + ::memcpy(cursor.m_position, m_memory.Buffer(), bufferSize); + // Set the constant buffer + submitter->setRootConstantBufferView(index, circularHeap.getGpuHandle(cursor)); + break; + } + case BackingStyle::ResourceBacked: + { + // Set the constant buffer + submitter->setRootConstantBufferView(index, m_resource.getResource()->GetGPUVirtualAddress()); + break; + } + default: break; + } } - D3D12Resource m_resource; - D3D12Resource m_uploadResource; + BufferResourceImpl(Resource::Usage initialUsage, const Desc& desc): + Parent(desc), + m_mapFlavor(MapFlavor::HostRead), + m_initialUsage(initialUsage) + { + } + + static BackingStyle _calcResourceBackingStyle(Usage usage) + { + switch (usage) + { + case Usage::ConstantBuffer: return BackingStyle::MemoryBacked; + default: return BackingStyle::ResourceBacked; + } + } - BufferDesc m_desc; - List<uint8_t> m_memory; - MapFlavor m_mapFlavor; + BackingStyle m_backingStyle; ///< How the resource is 'backed' - either as a resource or cpu memory. Cpu memory is typically used for constant buffers. + D3D12Resource m_resource; ///< The resource typically in gpu memory + D3D12Resource m_uploadResource; ///< If the resource can be written to, and is in gpu memory (ie not Memory backed), will have upload resource + + Usage m_initialUsage; + + List<uint8_t> m_memory; ///< Cpu memory buffer, used if the m_backingStyle is MemoryBacked + MapFlavor m_mapFlavor; ///< If the resource is mapped holds the current mapping flavor + }; + + class TextureResourceImpl: public TextureResource + { + public: + typedef TextureResource Parent; + + TextureResourceImpl(Type type, const Desc& desc): + Parent(type, desc) + { + } + + D3D12Resource m_resource; }; + class InputLayoutImpl: public InputLayout { public: @@ -144,11 +212,10 @@ protected: int m_uavIndex = -1; int m_samplerIndex = -1; - D3D12Resource m_resource; - + RefPtr<Resource> m_resource; + int m_binding = 0; bool m_isOutput = false; - int m_bufferLength = 0; }; class BindingStateImpl: public BindingState @@ -184,18 +251,11 @@ protected: struct BoundVertexBuffer { - RefPtr<BufferImpl> m_buffer; + RefPtr<BufferResourceImpl> m_buffer; int m_stride; int m_offset; }; - struct Submitter - { - virtual void setRootConstantBufferView(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) = 0; - virtual void setRootDescriptorTable(int index, D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor) = 0; - virtual void setRootSignature(ID3D12RootSignature* rootSignature) = 0; - }; - struct BindParameters { enum @@ -270,12 +330,11 @@ protected: void releaseFrameResources(); Result createBuffer(const D3D12_RESOURCE_DESC& resourceDesc, const void* srcData, D3D12Resource& uploadResource, D3D12_RESOURCE_STATES finalState, D3D12Resource& resourceOut); - Result createTexture(const InputTextureDesc& inputDesc, const TextureData& texData, D3D12Resource& resourceOut); - + Result createInputSampler(const InputSamplerDesc& inputDesc, D3D12DescriptorHeap& samplerHeap, int samplerIndex); - Result createInputTexture(const InputTextureDesc& inputDesc, D3D12DescriptorHeap& viewHeap, int srvIndex, D3D12Resource& resourceOut); - Result createInputBuffer(InputBufferDesc& bufferDesc, const List<unsigned int>& bufferData, D3D12DescriptorHeap& viewHeap, int uavIndex, int srvIndex, - D3D12Resource& resourceOut); + 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(); @@ -308,7 +367,7 @@ protected: int m_commandListOpenCount = 0; ///< If >0 the command list should be open List<BoundVertexBuffer> m_boundVertexBuffers; - List<RefPtr<BufferImpl> > m_boundConstantBuffers; + List<RefPtr<BufferResourceImpl> > m_boundConstantBuffers; RefPtr<ShaderProgramImpl> m_boundShaderProgram; RefPtr<InputLayoutImpl> m_boundInputLayout; @@ -595,253 +654,44 @@ Result D3D12Renderer::createBuffer(const D3D12_RESOURCE_DESC& resourceDesc, cons return SLANG_OK; } -Result D3D12Renderer::createTexture(const InputTextureDesc& inputDesc, const TextureData& texData, D3D12Resource& resourceOut) +Result D3D12Renderer::createInputTexture(const InputTextureDesc& inputDesc, D3D12DescriptorHeap& viewHeap, int srvIndex, RefPtr<Resource>& resourceOut) { - // Description of uploading on Dx12 - // https://msdn.microsoft.com/en-us/library/windows/desktop/dn899215%28v=vs.85%29.aspx - - const DXGI_FORMAT pixelFormat = DXGI_FORMAT_R8G8B8A8_UNORM; - const int numMipMaps = texData.mipLevels; - - const int width = inputDesc.size; - // If the dimension is 1, then we have no height - const int height = (inputDesc.dimension <= 1) ? 1 : width; - const int depth = (inputDesc.dimension <= 2) ? 1 : width; - - // Setup desc - D3D12_RESOURCE_DESC resourceDesc; - - resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; - resourceDesc.Format = pixelFormat; - resourceDesc.Width = width; - resourceDesc.Height = height; - resourceDesc.DepthOrArraySize = (depth > 1) ? depth : texData.arraySize; - - resourceDesc.MipLevels = numMipMaps; - resourceDesc.SampleDesc.Count = 1; - resourceDesc.SampleDesc.Quality = 0; - resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - resourceDesc.Alignment = 0; - - switch (inputDesc.dimension) - { - case 1: resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D; break; - case 2: resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; break; - case 3: resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; break; - default: return SLANG_FAIL; - } - - // Create the target resource - { - D3D12_HEAP_PROPERTIES heapProps; - - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - SLANG_RETURN_ON_FAIL(resourceOut.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr)); - - resourceOut.setDebugName(L"Texture"); - } - - // Calculate the layout - List<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> layouts; - layouts.SetSize(numMipMaps); - List<UInt64> mipRowSizeInBytes; - mipRowSizeInBytes.SetSize(numMipMaps); - List<UInt32> mipNumRows; - mipNumRows.SetSize(numMipMaps); - - UInt64 requiredSize = 0; - m_device->GetCopyableFootprints(&resourceDesc, 0, texData.mipLevels, 0, layouts.begin(), mipNumRows.begin(), mipRowSizeInBytes.begin(), &requiredSize); - -#if 0 - List<D3D12_SUBRESOURCE_DATA> subData; - subData.SetSize(numMipMaps); - // Zero it all initially - ::memset(subData.Buffer(), 0, numMipMaps * sizeof(D3D12_SUBRESOURCE_DATA)); -#endif - - // - assert(texData.dataBuffer.Count() == numMipMaps * texData.arraySize); - - // Sub resource indexing - // https://msdn.microsoft.com/en-us/library/windows/desktop/dn705766(v=vs.85).aspx#subresource_indexing - - int subResourceIndex = 0; - for (int i = 0; i < texData.arraySize; i++) + int bindFlags = 0; + if (srvIndex >= 0) { - // Create the upload texture - D3D12Resource uploadTexture; - { - D3D12_HEAP_PROPERTIES heapProps; - - heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - D3D12_RESOURCE_DESC uploadResourceDesc; - - uploadResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - uploadResourceDesc.Format = DXGI_FORMAT_UNKNOWN; - uploadResourceDesc.Width = requiredSize; - uploadResourceDesc.Height = 1; - uploadResourceDesc.DepthOrArraySize = 1; - uploadResourceDesc.MipLevels = 1; - uploadResourceDesc.SampleDesc.Count = 1; - uploadResourceDesc.SampleDesc.Quality = 0; - uploadResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - uploadResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - uploadResourceDesc.Alignment = 0; - - SLANG_RETURN_ON_FAIL(uploadTexture.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, uploadResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr)); - - uploadTexture.setDebugName(L"TextureUpload"); - } - - ID3D12Resource* uploadResource = uploadTexture; - - uint8_t* p; - uploadResource->Map(0, nullptr, reinterpret_cast<void**>(&p)); - - for (int j = 0; j < numMipMaps; ++j) - { - const D3D12_PLACED_SUBRESOURCE_FOOTPRINT& layout = layouts[j]; - const D3D12_SUBRESOURCE_FOOTPRINT& footprint = layout.Footprint; - - int mipWidth = width >> j; - mipWidth = (mipWidth <= 0) ? 1 : mipWidth; - - int mipHeight = height >> j; - mipHeight = (mipHeight <= 0) ? 1 : mipHeight; - - int mipDepth = depth >> j; - mipDepth = (mipDepth <= 0) ? 1 : mipDepth; - - assert(footprint.Width == mipWidth && footprint.Height == mipHeight && footprint.Depth == mipDepth); - - // NOTE! Like the D3D11 implementation -> this repeats the same mip pixels to every target (!) - const List<uint32_t>& srcMip = texData.dataBuffer[j]; - - // Check the input data is the same size as expected - assert(mipWidth * mipHeight * mipDepth == srcMip.Count()); - - const ptrdiff_t dstMipRowPitch = ptrdiff_t(layouts[j].Footprint.RowPitch); - const ptrdiff_t srcMipRowPitch = ptrdiff_t(sizeof(uint32_t) * mipWidth); - - assert(dstMipRowPitch >= srcMipRowPitch); - - const uint8_t* srcRow = (const uint8_t*)srcMip.Buffer(); - uint8_t* dstRow = p + layouts[j].Offset; - - // Copy the depth each mip - for (int l = 0; l < mipDepth; l++) - { - // Copy rows - for (int k = 0; k < mipHeight; ++k) - { - ::memcpy(dstRow, srcRow, srcMipRowPitch); - - srcRow += srcMipRowPitch; - dstRow += dstMipRowPitch; - } - } - - assert(srcRow == (const uint8_t*)(srcMip.Buffer() + srcMip.Count())); - } - uploadResource->Unmap(0, nullptr); - - for (int mipIndex = 0; mipIndex < numMipMaps; ++mipIndex) - { - // https://msdn.microsoft.com/en-us/library/windows/desktop/dn903862(v=vs.85).aspx - - D3D12_TEXTURE_COPY_LOCATION src; - src.pResource = uploadTexture; - src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - src.PlacedFootprint = layouts[mipIndex]; - - D3D12_TEXTURE_COPY_LOCATION dst; - dst.pResource = resourceOut; - dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dst.SubresourceIndex = subResourceIndex; - m_commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); - - subResourceIndex++; - } - - { - D3D12BarrierSubmitter submitter(m_commandList); - resourceOut.transition(D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, submitter); - } - - // Block - waiting for copy to complete (so can drop upload texture) - submitGpuWorkAndWait(); + bindFlags |= Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource; } - return SLANG_OK; -} - -Result D3D12Renderer::createInputTexture(const InputTextureDesc& inputDesc, D3D12DescriptorHeap& viewHeap, int srvIndex, D3D12Resource& resourceOut) -{ - TextureData texData; - generateTextureData(texData, inputDesc); + RefPtr<TextureResource> texture; + SLANG_RETURN_ON_FAIL(generateTextureResource(inputDesc, bindFlags, this, texture)); - SLANG_RETURN_ON_FAIL(createTexture(inputDesc, texData, resourceOut)); + TextureResourceImpl* textureImpl = static_cast<TextureResourceImpl*>(texture.Ptr()); if (srvIndex >= 0) { - const D3D12_RESOURCE_DESC resourceDesc = resourceOut.getResource()->GetDesc(); - - DXGI_FORMAT pixelFormat = resourceDesc.Format; + 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(resourceOut, &srvDesc, viewHeap.getCpuHandle(srvIndex)); + m_device->CreateShaderResourceView(textureImpl->m_resource, &srvDesc, viewHeap.getCpuHandle(srvIndex)); } + resourceOut = texture.Ptr(); return SLANG_OK; } -Result D3D12Renderer::createInputBuffer(InputBufferDesc& bufferDesc, const List<unsigned int>& bufferData, D3D12DescriptorHeap& viewHeap, int uavIndex, int srvIndex, - D3D12Resource& bufferOut) +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); - //bufferSize = D3DUtil::calcAligned(bufferSize, 256); - - D3D12_RESOURCE_DESC resourceDesc; - _initBufferResourceDesc(bufferSize, resourceDesc); - - D3D12_RESOURCE_STATES finalState = D3D12_RESOURCE_STATE_GENERIC_READ; - - if (bufferDesc.type == InputBufferType::ConstantBuffer) - { - finalState = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; - } - else - { - finalState = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - - /* if (bufferDesc.stride != 0) - { - desc.StructureByteStride = bufferDesc.stride; - desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; - } - else - { - desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; - } */ - } + + RefPtr<BufferResource> resource; + SLANG_RETURN_ON_FAIL(createInputBufferResource(bufferDesc, isOutput, bufferSize, bufferData.Buffer(), this, resource)); - D3D12Resource uploadBuffer; - SLANG_RETURN_ON_FAIL(createBuffer(resourceDesc, bufferData.Buffer(), uploadBuffer, finalState, bufferOut)); + BufferResourceImpl* resourceImpl = static_cast<BufferResourceImpl*>(resource.Ptr()); const int elemSize = bufferDesc.stride <= 0 ? sizeof(uint32_t) : bufferDesc.stride; @@ -870,7 +720,7 @@ Result D3D12Renderer::createInputBuffer(InputBufferDesc& bufferDesc, const List< uavDesc.Buffer.StructureByteStride = 0; } - m_device->CreateUnorderedAccessView(bufferOut.getResource(), nullptr, &uavDesc, viewHeap.getCpuHandle(uavIndex)); + m_device->CreateUnorderedAccessView(resourceImpl->m_resource, nullptr, &uavDesc, viewHeap.getCpuHandle(uavIndex)); } if (srvIndex >= 0) @@ -893,9 +743,11 @@ Result D3D12Renderer::createInputBuffer(InputBufferDesc& bufferDesc, const List< srvDesc.Format = DXGI_FORMAT_R32_FLOAT; } - m_device->CreateShaderResourceView(bufferOut.getResource(), &srvDesc, viewHeap.getCpuHandle(srvIndex)); + m_device->CreateShaderResourceView(resourceImpl->m_resource, &srvDesc, viewHeap.getCpuHandle(srvIndex)); } + bufferOut = resource.detach(); + return SLANG_OK; } @@ -1251,7 +1103,7 @@ D3D12Renderer::RenderState* D3D12Renderer::findRenderState(ProgramType programTy { switch (programType) { - case ProgramType::kCompute: + case ProgramType::Compute: { // Check if current state is a match if (m_currentRenderState) @@ -1275,7 +1127,7 @@ D3D12Renderer::RenderState* D3D12Renderer::findRenderState(ProgramType programTy } break; } - case ProgramType::kGraphics: + case ProgramType::Graphics: { if (m_currentRenderState) { @@ -1327,7 +1179,7 @@ D3D12Renderer::RenderState* D3D12Renderer::calcRenderState() switch (m_boundShaderProgram->m_programType) { - case ProgramType::kCompute: + case ProgramType::Compute: { if (SLANG_FAILED(calcComputePipelineState(rootSignature, pipelineState))) { @@ -1335,7 +1187,7 @@ D3D12Renderer::RenderState* D3D12Renderer::calcRenderState() } break; } - case ProgramType::kGraphics: + case ProgramType::Graphics: { if (SLANG_FAILED(calcGraphicsPipelineState(rootSignature, pipelineState))) { @@ -1367,14 +1219,13 @@ Result D3D12Renderer::_calcBindParameters(BindParameters& params) { int numConstantBuffers = 0; { - - if (m_boundBindingState) { const int numBoundConstantBuffers = numConstantBuffers; for (int i = 0; i < int(m_boundBindingState->m_bindings.Count()); i++) { const Binding& binding = m_boundBindingState->m_bindings[i]; + if (binding.m_type == ShaderInputType::Buffer && binding.m_bufferType == InputBufferType::ConstantBuffer) { // Make sure it's not overlapping the ones we just statically defined @@ -1390,7 +1241,7 @@ Result D3D12Renderer::_calcBindParameters(BindParameters& params) numConstantBuffers++; } - + if (binding.m_srvIndex >= 0) { D3D12_DESCRIPTOR_RANGE& range = params.nextRange(); @@ -1438,9 +1289,11 @@ Result D3D12Renderer::_calcBindParameters(BindParameters& params) // Okay we need to try and create a render state for (int i = 0; i < int(m_boundConstantBuffers.Count()); i++) { - const BufferImpl* buffer = m_boundConstantBuffers[i]; + const BufferResourceImpl* buffer = m_boundConstantBuffers[i]; if (buffer) { + assert(buffer->m_backingStyle == BufferResourceImpl::BackingStyle::MemoryBacked); + D3D12_ROOT_PARAMETER& param = params.nextParameter(); param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; @@ -1510,9 +1363,11 @@ Result D3D12Renderer::_bindRenderState(RenderState* renderState, ID3D12GraphicsC for (int i = 0; i < int(bindingState->m_bindings.Count()); i++) { const Binding& binding = bindingState->m_bindings[i]; + if (binding.m_type == ShaderInputType::Buffer && binding.m_bufferType == InputBufferType::ConstantBuffer) { - submitter->setRootConstantBufferView(index++, binding.m_resource.getResource()->GetGPUVirtualAddress()); + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.m_resource.Ptr()); + buffer->bindConstantBufferView(m_circularResourceHeap, index++, submitter); numConstantBuffers++; } @@ -1531,16 +1386,10 @@ Result D3D12Renderer::_bindRenderState(RenderState* renderState, ID3D12GraphicsC // Okay we need to try and create a render state for (int i = 0; i < int(m_boundConstantBuffers.Count()); i++) { - const BufferImpl* buffer = m_boundConstantBuffers[i]; + const BufferResourceImpl* buffer = m_boundConstantBuffers[i]; if (buffer) { - size_t bufferSize = buffer->m_memory.Count(); - - D3D12CircularResourceHeap::Cursor cursor = m_circularResourceHeap.allocateConstantBuffer(bufferSize); - ::memcpy(cursor.m_position, buffer->m_memory.Buffer(), bufferSize); - // Set the constant buffer - submitter->setRootConstantBufferView(index++, m_circularResourceHeap.getGpuHandle(cursor)); - + buffer->bindConstantBufferView(m_circularResourceHeap, index++, submitter); numConstantBuffers++; } } @@ -1552,8 +1401,6 @@ Result D3D12Renderer::_bindRenderState(RenderState* renderState, ID3D12GraphicsC } } - - return SLANG_OK; } @@ -2001,32 +1848,290 @@ ShaderCompiler* D3D12Renderer::getShaderCompiler() return this; } -Buffer* D3D12Renderer::createBuffer(const BufferDesc& desc) +static D3D12_RESOURCE_STATES _calcResourceState(Resource::Usage usage) +{ + typedef Resource::Usage Usage; + switch (usage) + { + case Usage::VertexBuffer: return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; + case Usage::IndexBuffer: return D3D12_RESOURCE_STATE_INDEX_BUFFER; + case Usage::ConstantBuffer: return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; + case Usage::StreamOutput: return D3D12_RESOURCE_STATE_STREAM_OUT; + case Usage::RenderTarget: return D3D12_RESOURCE_STATE_RENDER_TARGET; + case Usage::DepthWrite: return D3D12_RESOURCE_STATE_DEPTH_WRITE; + case Usage::DepthRead: return D3D12_RESOURCE_STATE_DEPTH_READ; + case Usage::UnorderedAccess: return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + case Usage::PixelShaderResource: return D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + case Usage::NonPixelShaderResource: return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + case Usage::GenericRead: return D3D12_RESOURCE_STATE_GENERIC_READ; + default: return D3D12_RESOURCE_STATES(0); + } +} + +static D3D12_RESOURCE_FLAGS _calcResourceFlag(Resource::BindFlag::Enum bindFlag) { - RefPtr<BufferImpl> buffer(new BufferImpl(desc)); - const size_t bufferSize = desc.size; + typedef Resource::BindFlag BindFlag; + switch (bindFlag) + { + case BindFlag::RenderTarget: return D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + case BindFlag::DepthStencil: return D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + case BindFlag::UnorderedAccess: return D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + default: return D3D12_RESOURCE_FLAG_NONE; + } +} - switch (desc.flavor) +static D3D12_RESOURCE_FLAGS _calcResourceBindFlags(Resource::Usage initialUsage, int bindFlags) +{ + int dstFlags = 0; + while (bindFlags) { - case BufferFlavor::Constant: + int lsb = bindFlags & -bindFlags; + + dstFlags |= _calcResourceFlag(Resource::BindFlag::Enum(lsb)); + bindFlags &= ~lsb; + } + return D3D12_RESOURCE_FLAGS(dstFlags); +} + +static D3D12_RESOURCE_DIMENSION _calcResourceDimension(Resource::Type type) +{ + switch (type) + { + case Resource::Type::Buffer: return D3D12_RESOURCE_DIMENSION_BUFFER; + case Resource::Type::Texture1D: return D3D12_RESOURCE_DIMENSION_TEXTURE1D; + case Resource::Type::TextureCube: + case Resource::Type::Texture2D: + { + return D3D12_RESOURCE_DIMENSION_TEXTURE2D; + } + case Resource::Type::Texture3D: return D3D12_RESOURCE_DIMENSION_TEXTURE3D; + default: return D3D12_RESOURCE_DIMENSION_UNKNOWN; + } +} + +TextureResource* D3D12Renderer::createTextureResource(Resource::Type type, Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData) +{ + // Description of uploading on Dx12 + // https://msdn.microsoft.com/en-us/library/windows/desktop/dn899215%28v=vs.85%29.aspx + + TextureResource::Desc srcDesc(descIn); + srcDesc.setDefaults(type, initialUsage); + + const DXGI_FORMAT pixelFormat = D3DUtil::getMapFormat(srcDesc.format); + if (pixelFormat == DXGI_FORMAT_UNKNOWN) + { + return nullptr; + } + + const int arraySize = srcDesc.calcEffectiveArraySize(type); + + const D3D12_RESOURCE_DIMENSION dimension = _calcResourceDimension(type); + if (dimension == D3D12_RESOURCE_DIMENSION_UNKNOWN) + { + return nullptr; + } + + const int numMipMaps = srcDesc.numMipLevels; + + // Setup desc + D3D12_RESOURCE_DESC resourceDesc; + + resourceDesc.Dimension = dimension; + resourceDesc.Format = pixelFormat; + resourceDesc.Width = srcDesc.size.width; + resourceDesc.Height = srcDesc.size.height; + resourceDesc.DepthOrArraySize = (srcDesc.size.depth > 1) ? srcDesc.size.depth : arraySize; + + resourceDesc.MipLevels = numMipMaps; + resourceDesc.SampleDesc.Count = srcDesc.sampleDesc.numSamples; + resourceDesc.SampleDesc.Quality = srcDesc.sampleDesc.quality; + + resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + resourceDesc.Alignment = 0; + + RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(type, srcDesc)); + + // Create the target resource + { + D3D12_HEAP_PROPERTIES heapProps; + + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 1; + heapProps.VisibleNodeMask = 1; + + SLANG_RETURN_NULL_ON_FAIL(texture->m_resource.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr)); + + texture->m_resource.setDebugName(L"Texture"); + } + + // Calculate the layout + List<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> layouts; + layouts.SetSize(numMipMaps); + List<UInt64> mipRowSizeInBytes; + mipRowSizeInBytes.SetSize(numMipMaps); + List<UInt32> mipNumRows; + mipNumRows.SetSize(numMipMaps); + + // Since textures are effectively immutable currently initData must be set + assert(initData); + // We should have this many sub resources + assert(initData->numSubResources == numMipMaps * srcDesc.size.depth * arraySize); + + // This is just the size for one array upload -> not for the whole texure + UInt64 requiredSize = 0; + m_device->GetCopyableFootprints(&resourceDesc, 0, numMipMaps, 0, layouts.begin(), mipNumRows.begin(), mipRowSizeInBytes.begin(), &requiredSize); + + // Sub resource indexing + // https://msdn.microsoft.com/en-us/library/windows/desktop/dn705766(v=vs.85).aspx#subresource_indexing + + int subResourceIndex = 0; + for (int i = 0; i < arraySize; i++) + { + // Create the upload texture + D3D12Resource uploadTexture; + { + D3D12_HEAP_PROPERTIES heapProps; + + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 1; + heapProps.VisibleNodeMask = 1; + + D3D12_RESOURCE_DESC uploadResourceDesc; + + uploadResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + uploadResourceDesc.Format = DXGI_FORMAT_UNKNOWN; + uploadResourceDesc.Width = requiredSize; + uploadResourceDesc.Height = 1; + uploadResourceDesc.DepthOrArraySize = 1; + uploadResourceDesc.MipLevels = 1; + uploadResourceDesc.SampleDesc.Count = 1; + uploadResourceDesc.SampleDesc.Quality = 0; + uploadResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + uploadResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + uploadResourceDesc.Alignment = 0; + + SLANG_RETURN_NULL_ON_FAIL(uploadTexture.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, uploadResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr)); + + uploadTexture.setDebugName(L"TextureUpload"); + } + + ID3D12Resource* uploadResource = uploadTexture; + + uint8_t* p; + uploadResource->Map(0, nullptr, reinterpret_cast<void**>(&p)); + + for (int j = 0; j < numMipMaps; ++j) + { + const D3D12_PLACED_SUBRESOURCE_FOOTPRINT& layout = layouts[j]; + const D3D12_SUBRESOURCE_FOOTPRINT& footprint = layout.Footprint; + + const TextureResource::Size mipSize = srcDesc.size.calcMipSize(j); + + assert(footprint.Width == mipSize.width && footprint.Height == mipSize.height && footprint.Depth == mipSize.depth); + + const ptrdiff_t dstMipRowPitch = ptrdiff_t(layouts[j].Footprint.RowPitch); + const ptrdiff_t srcMipRowPitch = ptrdiff_t(initData->mipRowStrides[j]); + + assert(dstMipRowPitch >= srcMipRowPitch); + + const uint8_t* srcRow = (const uint8_t*)initData->subResources[subResourceIndex]; + uint8_t* dstRow = p + layouts[j].Offset; + + // Copy the depth each mip + for (int l = 0; l < mipSize.depth; l++) + { + // Copy rows + for (int k = 0; k < mipSize.height; ++k) + { + ::memcpy(dstRow, srcRow, srcMipRowPitch); + + srcRow += srcMipRowPitch; + dstRow += dstMipRowPitch; + } + } + + //assert(srcRow == (const uint8_t*)(srcMip.Buffer() + srcMip.Count())); + } + uploadResource->Unmap(0, nullptr); + + for (int mipIndex = 0; mipIndex < numMipMaps; ++mipIndex) + { + // https://msdn.microsoft.com/en-us/library/windows/desktop/dn903862(v=vs.85).aspx + + D3D12_TEXTURE_COPY_LOCATION src; + src.pResource = uploadTexture; + src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + src.PlacedFootprint = layouts[mipIndex]; + + D3D12_TEXTURE_COPY_LOCATION dst; + dst.pResource = texture->m_resource; + dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dst.SubresourceIndex = subResourceIndex; + m_commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); + + subResourceIndex++; + } + + { + // const D3D12_RESOURCE_STATES finalState = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + const D3D12_RESOURCE_STATES finalState = _calcResourceState(initialUsage); + + D3D12BarrierSubmitter submitter(m_commandList); + texture->m_resource.transition(finalState, submitter); + } + + // Block - waiting for copy to complete (so can drop upload texture) + submitGpuWorkAndWait(); + } + + return texture.detach(); +} + +BufferResource* D3D12Renderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData) +{ + typedef BufferResourceImpl::BackingStyle Style; + + BufferResource::Desc srcDesc(descIn); + srcDesc.setDefaults(initialUsage); + + RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(initialUsage, srcDesc)); + + // Save the style + buffer->m_backingStyle = BufferResourceImpl::_calcResourceBackingStyle(initialUsage); + + D3D12_RESOURCE_DESC bufferDesc; + _initBufferResourceDesc(srcDesc.sizeInBytes, bufferDesc); + + bufferDesc.Flags = _calcResourceBindFlags(initialUsage, srcDesc.bindFlags); + + switch (buffer->m_backingStyle) + { + case Style::MemoryBacked: { // Assume the constant buffer will change every frame. We'll just keep a copy of the contents // in regular memory until it needed - buffer->m_memory.SetSize(UInt(bufferSize)); - break; + buffer->m_memory.SetSize(UInt(srcDesc.sizeInBytes)); + // Initialize + if (initData) + { + ::memcpy(buffer->m_memory.Buffer(), initData, srcDesc.sizeInBytes); + } + break; } - case BufferFlavor::Vertex: + case Style::ResourceBacked: { - D3D12_RESOURCE_DESC bufferDesc; - _initBufferResourceDesc(bufferSize, bufferDesc); - - SLANG_RETURN_NULL_ON_FAIL(createBuffer(bufferDesc, desc.initData, buffer->m_uploadResource, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, buffer->m_resource)); + const D3D12_RESOURCE_STATES initialState = _calcResourceState(initialUsage); + SLANG_RETURN_NULL_ON_FAIL(createBuffer(bufferDesc, initData, buffer->m_uploadResource, initialState, buffer->m_resource)); break; } - default: - return nullptr; + default: return nullptr; } - + return buffer.detach(); } @@ -2076,17 +2181,19 @@ InputLayout* D3D12Renderer::createInputLayout(const InputElementDesc* inputEleme return layout.detach(); } -void* D3D12Renderer::map(Buffer* bufferIn, MapFlavor flavor) +void* D3D12Renderer::map(BufferResource* bufferIn, MapFlavor flavor) { - BufferImpl* buffer = static_cast<BufferImpl*>(bufferIn); + typedef BufferResourceImpl::BackingStyle Style; + + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn); buffer->m_mapFlavor = flavor; - switch (buffer->m_desc.flavor) + const size_t bufferSize = buffer->getDesc().sizeInBytes; + + switch (buffer->m_backingStyle) { - case BufferFlavor::Vertex: + case Style::ResourceBacked: { - D3D12_RANGE readRange = {}; // We do not intend to read from this resource on the CPU. - // We need this in a state so we can upload switch (flavor) { @@ -2096,72 +2203,129 @@ void* D3D12Renderer::map(Buffer* bufferIn, MapFlavor flavor) D3D12BarrierSubmitter submitter(m_commandList); buffer->m_uploadResource.transition(D3D12_RESOURCE_STATE_GENERIC_READ, submitter); buffer->m_resource.transition(D3D12_RESOURCE_STATE_COPY_DEST, submitter); + + const D3D12_RANGE readRange = {}; + + void* uploadData; + SLANG_RETURN_NULL_ON_FAIL(buffer->m_uploadResource.getResource()->Map(0, &readRange, reinterpret_cast<void**>(&uploadData))); + return uploadData; + break; } - case MapFlavor::HostRead: + case MapFlavor::HostRead: { - // Lock whole of the buffer - readRange.End = buffer->m_desc.size; - break; + // This will be slow!!! - it blocks CPU on GPU completion + D3D12Resource& resource = buffer->m_resource; + + // Readback heap + D3D12_HEAP_PROPERTIES heapProps; + heapProps.Type = D3D12_HEAP_TYPE_READBACK; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 1; + heapProps.VisibleNodeMask = 1; + + // Resource to readback to + D3D12_RESOURCE_DESC stagingDesc; + _initBufferResourceDesc(bufferSize, stagingDesc); + + D3D12Resource stageBuf; + SLANG_RETURN_NULL_ON_FAIL(stageBuf.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, stagingDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr)); + + const D3D12_RESOURCE_STATES initialState = resource.getState(); + + // Make it a source + { + D3D12BarrierSubmitter submitter(m_commandList); + resource.transition(D3D12_RESOURCE_STATE_COPY_SOURCE, submitter); + } + // Do the copy + m_commandList->CopyBufferRegion(stageBuf, 0, resource, 0, bufferSize); + // Switch it back + { + D3D12BarrierSubmitter submitter(m_commandList); + resource.transition(initialState, submitter); + } + + // Wait until complete + submitGpuWorkAndWait(); + + // Map and copy + { + UINT8* data; + D3D12_RANGE readRange = { 0, bufferSize }; + + SLANG_RETURN_NULL_ON_FAIL(stageBuf.getResource()->Map(0, &readRange, reinterpret_cast<void**>(&data))); + + // Copy to memory buffer + buffer->m_memory.SetSize(bufferSize); + ::memcpy(buffer->m_memory.Buffer(), data, bufferSize); + + stageBuf.getResource()->Unmap(0, nullptr); + } + + return buffer->m_memory.Buffer(); } } - - // Lock it - void* uploadData; - SLANG_RETURN_NULL_ON_FAIL(buffer->m_uploadResource.getResource()->Map(0, &readRange, reinterpret_cast<void**>(&uploadData))); - return uploadData; + break; } - case BufferFlavor::Constant: + case Style::MemoryBacked: { return buffer->m_memory.Buffer(); } + default: return nullptr; } return nullptr; } -void D3D12Renderer::unmap(Buffer* buffer) +void D3D12Renderer::unmap(BufferResource* bufferIn) { - BufferImpl* impl = static_cast<BufferImpl*>(buffer); + typedef BufferResourceImpl::BackingStyle Style; + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn); - switch (impl->m_desc.flavor) + switch (buffer->m_backingStyle) { - case BufferFlavor::Vertex: + case Style::MemoryBacked: + { + // Don't need to do anything, as will be uploaded automatically when used + break; + } + case Style::ResourceBacked: { - // Unmap - ID3D12Resource* uploadResource = impl->m_uploadResource; - ID3D12Resource* resource = impl->m_resource; - - uploadResource->Unmap(0, nullptr); - // We need this in a state so we can upload - switch (impl->m_mapFlavor) + switch (buffer->m_mapFlavor) { case MapFlavor::HostWrite: case MapFlavor::WriteDiscard: { + // Unmap + ID3D12Resource* uploadResource = buffer->m_uploadResource; + ID3D12Resource* resource = buffer->m_resource; + + uploadResource->Unmap(0, nullptr); + + const D3D12_RESOURCE_STATES initialState = buffer->m_resource.getState(); + { D3D12BarrierSubmitter submitter(m_commandList); - impl->m_uploadResource.transition(D3D12_RESOURCE_STATE_GENERIC_READ, submitter); - impl->m_resource.transition(D3D12_RESOURCE_STATE_COPY_DEST, submitter); + buffer->m_uploadResource.transition(D3D12_RESOURCE_STATE_GENERIC_READ, submitter); + buffer->m_resource.transition(D3D12_RESOURCE_STATE_COPY_DEST, submitter); } - m_commandList->CopyBufferRegion(resource, 0, uploadResource, 0, impl->m_desc.size); + m_commandList->CopyBufferRegion(resource, 0, uploadResource, 0, buffer->getDesc().sizeInBytes); { D3D12BarrierSubmitter submitter(m_commandList); - impl->m_resource.transition(D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, submitter); + buffer->m_resource.transition(initialState, submitter); } - break; } - case MapFlavor::HostRead: break; + case MapFlavor::HostRead: + { + break; + } } - break; - } - case BufferFlavor::Constant: - { - break; } } } @@ -2188,7 +2352,7 @@ void D3D12Renderer::setPrimitiveTopology(PrimitiveTopology topology) } } -void D3D12Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* strides, const UInt* offsets) +void D3D12Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) { { const UInt num = startSlot + slotCount; @@ -2200,10 +2364,10 @@ void D3D12Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, Buffer*cons for (UInt i = 0; i < slotCount; i++) { - BufferImpl* buffer = static_cast<BufferImpl*>(buffers[i]); + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[i]); if (buffer) { - assert(buffer->m_desc.flavor == BufferFlavor::Vertex); + assert(buffer->m_initialUsage == Resource::Usage::VertexBuffer); } BoundVertexBuffer& boundBuffer = m_boundVertexBuffers[startSlot + i]; @@ -2218,7 +2382,7 @@ void D3D12Renderer::setShaderProgram(ShaderProgram* inProgram) m_boundShaderProgram = static_cast<ShaderProgramImpl*>(inProgram); } -void D3D12Renderer::setConstantBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* offsets) +void D3D12Renderer::setConstantBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets) { { const UInt num = startSlot + slotCount; @@ -2230,10 +2394,10 @@ void D3D12Renderer::setConstantBuffers(UInt startSlot, UInt slotCount, Buffer*co for (UInt i = 0; i < slotCount; i++) { - BufferImpl* buffer = static_cast<BufferImpl*>(buffers[i]); + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[i]); if (buffer) { - assert(buffer->m_desc.flavor == BufferFlavor::Constant); + assert(buffer->m_initialUsage == Resource::Usage::ConstantBuffer); } m_boundConstantBuffers[startSlot + i] = buffer; } @@ -2267,12 +2431,12 @@ void D3D12Renderer::draw(UInt vertexCount, UInt startVertex) for (int i = 0; i < int(m_boundVertexBuffers.Count()); i++) { const BoundVertexBuffer& boundVertexBuffer = m_boundVertexBuffers[i]; - BufferImpl* buffer = boundVertexBuffer.m_buffer; + BufferResourceImpl* buffer = boundVertexBuffer.m_buffer; if (buffer) { D3D12_VERTEX_BUFFER_VIEW& vertexView = vertexViews[numVertexViews++]; vertexView.BufferLocation = buffer->m_resource.getResource()->GetGPUVirtualAddress(); - vertexView.SizeInBytes = int(buffer->m_desc.size); + vertexView.SizeInBytes = int(buffer->getDesc().sizeInBytes); vertexView.StrideInBytes = boundVertexBuffer.m_stride; } } @@ -2335,9 +2499,8 @@ BindingState* D3D12Renderer::createBindingState(const ShaderInputLayout& layout) } } - SLANG_RETURN_NULL_ON_FAIL(createInputBuffer(srcEntry.bufferDesc, srcEntry.bufferData, bindingState->m_viewHeap, dstEntry.m_uavIndex, dstEntry.m_srvIndex, dstEntry.m_resource)); + 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_bufferLength = (int)(srcEntry.bufferData.Count() * sizeof(unsigned int)); dstEntry.m_bufferType = srcEntry.bufferDesc.type; break; } @@ -2384,58 +2547,23 @@ void D3D12Renderer::serializeOutput(BindingState* stateIn, const char* fileName) auto bindingState = static_cast<BindingStateImpl*>(stateIn); FILE * f = fopen(fileName, "wb"); - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_READBACK; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - int id = 0; for (auto & binding : bindingState->m_bindings) { if (binding.m_isOutput) { - if (binding.m_resource.getResource()) + if (binding.m_resource && binding.m_resource->isBuffer()) { - // create staging buffer - //size_t bufferSize = D3DUtil::calcAligned(binding.m_bufferLength, 256); - const size_t bufferSize = binding.m_bufferLength; - - D3D12_RESOURCE_DESC stagingDesc; - _initBufferResourceDesc(bufferSize, stagingDesc); - - D3D12Resource stageBuf; - SLANG_RETURN_VOID_ON_FAIL(stageBuf.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, stagingDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr)); - - const D3D12_RESOURCE_STATES initialState = binding.m_resource.getState(); - - // Make it a source - { - D3D12BarrierSubmitter submitter(m_commandList); - binding.m_resource.transition(D3D12_RESOURCE_STATE_COPY_SOURCE, submitter); - } - // Do the copy - m_commandList->CopyBufferRegion(stageBuf, 0, binding.m_resource, 0, bufferSize); - // Switch it back - { - D3D12BarrierSubmitter submitter(m_commandList); - binding.m_resource.transition(initialState, submitter); - } + BufferResource* bufferResource = static_cast<BufferResource*>(binding.m_resource.Ptr()); + const size_t bufferSize = bufferResource->getDesc().sizeInBytes; - // Wait until complete - submitGpuWorkAndWait(); + unsigned int* ptr = (unsigned int*)map(bufferResource, MapFlavor::HostRead); - UINT8* data; - D3D12_RANGE readRange = {0, bufferSize}; - - SLANG_RETURN_VOID_ON_FAIL(stageBuf.getResource()->Map(0, &readRange, reinterpret_cast<void**>(&data))); + for (auto i = 0u; i < bufferSize / sizeof(unsigned int); i++) { - auto ptr = (unsigned int *)data; - for (auto i = 0u; i < binding.m_bufferLength / sizeof(unsigned int); i++) - fprintf(f, "%X\n", ptr[i]); + fprintf(f, "%X\n", ptr[i]); } - stageBuf.getResource()->Unmap(0, nullptr); + unmap(bufferResource); } else { @@ -2455,7 +2583,7 @@ ShaderProgram* D3D12Renderer::compileProgram(const ShaderCompileRequest& request if (request.computeShader.name) { - program->m_programType = ProgramType::kCompute; + program->m_programType = ProgramType::Compute; ComPtr<ID3DBlob> computeShaderBlob; SLANG_RETURN_NULL_ON_FAIL(D3DUtil::compileHLSLShader(request.computeShader.source.path, request.computeShader.source.dataBegin, request.computeShader.name, request.computeShader.profile, computeShaderBlob)); @@ -2463,7 +2591,7 @@ ShaderProgram* D3D12Renderer::compileProgram(const ShaderCompileRequest& request } else { - program->m_programType = ProgramType::kGraphics; + program->m_programType = ProgramType::Graphics; ComPtr<ID3DBlob> vertexShaderBlob, fragmentShaderBlob; SLANG_RETURN_NULL_ON_FAIL(D3DUtil::compileHLSLShader(request.vertexShader.source.path, request.vertexShader.source.dataBegin, request.vertexShader.name, request.vertexShader.profile, vertexShaderBlob)); SLANG_RETURN_NULL_ON_FAIL(D3DUtil::compileHLSLShader(request.fragmentShader.source.path, request.fragmentShader.source.dataBegin, request.fragmentShader.name, request.fragmentShader.profile, fragmentShaderBlob)); diff --git a/tools/render-test/render-gl.cpp b/tools/render-test/render-gl.cpp index f888e72a2..27c3cdab4 100644 --- a/tools/render-test/render-gl.cpp +++ b/tools/render-test/render-gl.cpp @@ -11,6 +11,8 @@ #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... @@ -82,20 +84,21 @@ public: virtual void setClearColor(const float color[4]) override; virtual void clearFrame() override; virtual void presentFrame() override; + 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 Buffer* createBuffer(const BufferDesc& desc) override; virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override; virtual BindingState * createBindingState(const ShaderInputLayout& layout) override; virtual ShaderCompiler* getShaderCompiler() override; - virtual void* map(Buffer* buffer, MapFlavor flavor) override; - virtual void unmap(Buffer* buffer) override; + virtual void* map(BufferResource* buffer, MapFlavor flavor) override; + virtual void unmap(BufferResource* buffer) override; virtual void setInputLayout(InputLayout* inputLayout) override; virtual void setPrimitiveTopology(PrimitiveTopology topology) override; virtual void setBindingState(BindingState* state); - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* strides, const UInt* offsets) override; + virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override; virtual void setShaderProgram(ShaderProgram* inProgram) override; - virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* offsets) override; + virtual void setConstantBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets) override; virtual void draw(UInt vertexCount, UInt startVertex) override; virtual void dispatchCompute(int x, int y, int z) override; virtual void submitGpuWork() override {} @@ -131,34 +134,69 @@ public: UInt m_attributeCount = 0; }; - class BufferImpl: public Buffer + class BufferResourceImpl: public BufferResource { public: - BufferImpl(GLRenderer* renderer, GLuint id): + typedef BufferResource Parent; + + BufferResourceImpl(Usage initialUsage, const Desc& desc, GLRenderer* renderer, GLuint id, GLenum target): + Parent(desc), m_renderer(renderer), - m_id(id) + m_handle(id), + m_initialUsage(initialUsage), + m_target(target) {} - ~BufferImpl() + ~BufferResourceImpl() { if (m_renderer) { - m_renderer->glDeleteBuffers(1, &m_id); + m_renderer->glDeleteBuffers(1, &m_handle); } } + Usage m_initialUsage; GLRenderer* m_renderer; - GLuint m_id; + GLuint m_handle; + GLenum m_target; }; + class TextureResourceImpl: public TextureResource + { + public: + typedef TextureResource Parent; + + TextureResourceImpl(Type type, Usage initialUsage, const Desc& desc, GLRenderer* renderer): + Parent(type, desc), + m_initialUsage(initialUsage), + m_renderer(renderer) + { + m_target = 0; + m_handle = 0; + } + + ~TextureResourceImpl() + { + if (m_handle) + { + glDeleteTextures(1, &m_handle); + } + } + + Usage m_initialUsage; + GLRenderer* m_renderer; + GLenum m_target; + GLuint m_handle; + }; + struct BindingEntry { ShaderInputType type; - GLuint handle; + RefPtr<Resource> resource; + GLuint samplerHandle = 0; List<int> binding; - int bindTarget; - int bufferSize; bool isOutput = false; }; + class BindingStateImpl: public BindingState { public: @@ -199,17 +237,31 @@ public: GLRenderer* m_renderer; }; - void destroyBindingEntry(const BindingEntry& entry); + enum class GlPixelFormat + { + Unknown, + RGBA_Unorm_UInt8, + CountOf, + }; + + struct GlPixelFormatInfo + { + GLint internalFormat; // such as GL_RGBA8 + GLenum format; // such as GL_RGBA + GLenum formatType; // such as GL_UNSIGNED_BYTE + }; + void destroyBindingEntries(const BindingEntry* entries, int numEntries); - void bindBufferImpl(int target, UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* offsets); + void bindBufferImpl(int target, UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets); void flushStateForDraw(); GLuint loadShader(GLenum stage, char const* source); - void createInputBuffer(BindingEntry& rs, InputBufferDesc bufDesc, List<unsigned int>& bufferData); void debugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message); - void createInputTexture(BindingEntry& rs, InputTextureDesc texDesc, InputSamplerDesc samplerDesc); void createInputSampler(BindingEntry& rs, InputSamplerDesc samplerDesc); + /// Returns GlPixelFormat::Unknown if not an equivalent + static GlPixelFormat _getGlPixelFormat(Format format); + static void APIENTRY staticDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam); static VertexAttributeFormat getVertexAttributeFormat(Format format); @@ -230,6 +282,24 @@ public: #define DECLARE_GL_EXTENSION_FUNC(NAME, TYPE) TYPE NAME; MAP_GL_EXTENSION_FUNCS(DECLARE_GL_EXTENSION_FUNC) #undef DECLARE_GL_EXTENSION_FUNC + + static const GlPixelFormatInfo s_pixelFormatInfos[int(GlPixelFormat::CountOf)]; +}; + +/* static */GLRenderer::GlPixelFormat GLRenderer::_getGlPixelFormat(Format format) +{ + switch (format) + { + case Format::RGBA_Unorm_UInt8: return GlPixelFormat::RGBA_Unorm_UInt8; + default: return GlPixelFormat::Unknown; + } +} + +/* static */ const GLRenderer::GlPixelFormatInfo GLRenderer::s_pixelFormatInfos[int(GlPixelFormat::CountOf)] = +{ + // internalType, format, formatType + { 0, 0, 0}, // GlPixelFormat::Unknown + { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, // GlPixelFormat::RGBA_Unorm_UInt8 }; Renderer* createGLRenderer() @@ -268,18 +338,19 @@ void GLRenderer::debugCallback(GLenum source, GLenum type, GLuint id, GLenum sev CASE(RGB_Float32, 3, GL_FLOAT, GL_FALSE); CASE(RG_Float32, 2, GL_FLOAT, GL_FALSE); + CASE(R_Float32, 1, GL_FLOAT, GL_FALSE); #undef CASE } } -void GLRenderer::bindBufferImpl(int target, UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* offsets) +void GLRenderer::bindBufferImpl(int target, UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets) { for (UInt ii = 0; ii < slotCount; ++ii) { UInt slot = startSlot + ii; - BufferImpl* buffer = static_cast<BufferImpl*>(buffers[ii]); - GLuint bufferID = buffer ? buffer->m_id : 0; + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[ii]); + GLuint bufferID = buffer ? buffer->m_handle : 0; assert(!offsets || !offsets[ii]); @@ -426,158 +497,44 @@ GLuint GLRenderer::loadShader(GLenum stage, const char* source) return shaderID; } -void GLRenderer::destroyBindingEntry(const BindingEntry& entry) -{ - switch (entry.type) - { - case ShaderInputType::Buffer: - { - glDeleteBuffers(1, &entry.handle); - break; - } - case ShaderInputType::Texture: - case ShaderInputType::CombinedTextureSampler: - { - glDeleteTextures(1, &entry.handle); - break; - } - case ShaderInputType::Sampler: - { - glDeleteSamplers(1, &entry.handle); - break; - } - default: break; - } -} - void GLRenderer::destroyBindingEntries(const BindingEntry* entries, int numEntries) { for (int i = 0; i < numEntries; ++i) { - destroyBindingEntry(entries[i]); + const BindingEntry& entry = entries[i]; + if (entry.type == ShaderInputType::Sampler && entry.samplerHandle != 0) + { + glDeleteSamplers(1, &entry.samplerHandle); + } } } -void GLRenderer::createInputBuffer(BindingEntry& rs, InputBufferDesc bufDesc, List<unsigned int>& bufferData) +void GLRenderer::createInputSampler(BindingEntry& entry, InputSamplerDesc samplerDesc) { - rs.bindTarget = (bufDesc.type == InputBufferType::StorageBuffer ? GL_SHADER_STORAGE_BUFFER : GL_UNIFORM_BUFFER); - glGenBuffers(1, &rs.handle); - glBindBuffer(rs.bindTarget, rs.handle); - glBufferData(rs.bindTarget, bufferData.Count() * sizeof(unsigned int), bufferData.Buffer(), GL_STATIC_READ); - glBindBuffer(rs.bindTarget, 0); -} + GLuint handle; -void GLRenderer::createInputTexture(BindingEntry& rs, InputTextureDesc texDesc, InputSamplerDesc samplerDesc) -{ - TextureData texData; - generateTextureData(texData, texDesc); - glGenTextures(1, &rs.handle); - switch (texDesc.dimension) - { - case 1: - if (texDesc.arrayLength > 0) - { - rs.bindTarget = GL_TEXTURE_1D_ARRAY; - glBindTexture(rs.bindTarget, rs.handle); - int slice = 0; - for (int i = 0; i < texData.arraySize; i++) - { - for (int j = 0; j < texData.mipLevels; j++) - { - glTexImage2D(rs.bindTarget, j, GL_RGBA8, texData.textureSize, i, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData.dataBuffer[slice].Buffer()); - slice++; - } - } - } - else - { - rs.bindTarget = GL_TEXTURE_1D; - glBindTexture(rs.bindTarget, rs.handle); - for (int i = 0; i < texData.mipLevels; i++) - glTexImage1D(rs.bindTarget, i, GL_RGBA8, texData.textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData.dataBuffer[i].Buffer()); - } - break; - case 2: - if (texDesc.arrayLength > 0) - { - if (texDesc.isCube) - rs.bindTarget = GL_TEXTURE_CUBE_MAP_ARRAY; - else - rs.bindTarget = GL_TEXTURE_2D_ARRAY; - glBindTexture(rs.bindTarget, rs.handle); - for (auto i = 0u; i < texData.dataBuffer.Count(); i++) - glTexImage3D(rs.bindTarget, i % texData.mipLevels, GL_RGBA8, texData.textureSize, texData.textureSize, i, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData.dataBuffer[i].Buffer()); - } - else - { - if (texDesc.isCube) - { - rs.bindTarget = GL_TEXTURE_CUBE_MAP; - glBindTexture(rs.bindTarget, rs.handle); - for (int j = 0; j < 6; j++) - { - for (int i = 0; i < texData.mipLevels; i++) - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i, GL_RGBA8, texData.textureSize, texData.textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData.dataBuffer[i + j*texData.mipLevels].Buffer()); - } - } - else - { - rs.bindTarget = GL_TEXTURE_2D; - glBindTexture(rs.bindTarget, rs.handle); - for (int i = 0; i < texData.mipLevels; i++) - glTexImage2D(rs.bindTarget, i, GL_RGBA8, texData.textureSize, texData.textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData.dataBuffer[i].Buffer()); - } - } - break; - case 3: - rs.bindTarget = GL_TEXTURE_3D; - glBindTexture(rs.bindTarget, rs.handle); - for (int i = 0; i < texData.mipLevels; i++) - glTexImage3D(rs.bindTarget, i, GL_RGBA8, texData.textureSize, texData.textureSize, texData.textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData.dataBuffer[i].Buffer()); - break; - } - glTexParameteri(rs.bindTarget, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(rs.bindTarget, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(rs.bindTarget, GL_TEXTURE_WRAP_R, GL_REPEAT); + 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) { - glTexParameteri(rs.bindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(rs.bindTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(rs.bindTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f); + 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 { - glTexParameteri(rs.bindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(rs.bindTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(rs.bindTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(rs.bindTarget, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + 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); } -} -void GLRenderer::createInputSampler(BindingEntry& rs, InputSamplerDesc samplerDesc) -{ - glCreateSamplers(1, &rs.handle); - glSamplerParameteri(rs.handle, GL_TEXTURE_WRAP_S, GL_REPEAT); - glSamplerParameteri(rs.handle, GL_TEXTURE_WRAP_T, GL_REPEAT); - glSamplerParameteri(rs.handle, GL_TEXTURE_WRAP_R, GL_REPEAT); - - if (samplerDesc.isCompareSampler) - { - glSamplerParameteri(rs.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glSamplerParameteri(rs.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glSamplerParameteri(rs.handle, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8); - } - else - { - glSamplerParameteri(rs.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glSamplerParameteri(rs.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glSamplerParameteri(rs.handle, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glSamplerParameteri(rs.handle, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - } + entry.samplerHandle = handle; } - // !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! SlangResult GLRenderer::initialize(void* inWindowHandle) @@ -691,21 +648,187 @@ ShaderCompiler* GLRenderer::getShaderCompiler() return this; } -Buffer* GLRenderer::createBuffer(const BufferDesc& desc) +TextureResource* GLRenderer::createTextureResource(Resource::Type type, Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData) { - // TODO: should derive target from desc... - GLenum target = GL_UNIFORM_BUFFER; + TextureResource::Desc srcDesc(descIn); + srcDesc.setDefaults(type, initialUsage); - // TODO: should derive from desc... - GLenum usage = GL_DYNAMIC_DRAW; + GlPixelFormat pixelFormat = _getGlPixelFormat(srcDesc.format); + if (pixelFormat == GlPixelFormat::Unknown) + { + return nullptr; + } + + const GlPixelFormatInfo& info = s_pixelFormatInfos[int(pixelFormat)]; + + const GLint internalFormat = info.internalFormat; + const GLenum format = info.format; + const GLenum formatType = info.formatType; + + RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(type, initialUsage, srcDesc, this)); + + GLenum target = 0; + GLuint handle = 0; + glGenTextures(1, &handle); + + const int effectiveArraySize = srcDesc.calcEffectiveArraySize(type); + + assert(initData); + assert(initData->numSubResources == srcDesc.numMipLevels * srcDesc.size.depth * effectiveArraySize); + + // Set on texture so will be freed if failure + texture->m_handle = handle; + const void*const*const data = initData->subResources; + + switch (type) + { + case Resource::Type::Texture1D: + { + if (srcDesc.arraySize > 0) + { + target = GL_TEXTURE_1D_ARRAY; + glBindTexture(target, handle); + int slice = 0; + for (int i = 0; i < effectiveArraySize; i++) + { + for (int j = 0; j < srcDesc.numMipLevels; j++) + { + glTexImage2D(target, j, internalFormat, srcDesc.size.width, i, 0, format, formatType, data[slice++]); + } + } + } + else + { + target = GL_TEXTURE_1D; + glBindTexture(target, handle); + for (int i = 0; i < srcDesc.numMipLevels; i++) + { + glTexImage1D(target, i, internalFormat, srcDesc.size.width, 0, format, formatType, data[i]); + } + } + break; + } + case Resource::Type::TextureCube: + case Resource::Type::Texture2D: + { + if (srcDesc.arraySize > 0) + { + if (type == Resource::Type::TextureCube) + { + target = GL_TEXTURE_CUBE_MAP_ARRAY; + } + else + { + target = GL_TEXTURE_2D_ARRAY; + } + + glBindTexture(target, handle); + + int slice = 0; + for (int i = 0; i < effectiveArraySize; i++) + { + for (int j = 0; j < srcDesc.numMipLevels; j++) + { + glTexImage3D(target, j, internalFormat, srcDesc.size.width, srcDesc.size.height, slice, 0, format, formatType, data[slice++]); + } + } + } + else + { + if (type == Resource::Type::TextureCube) + { + target = GL_TEXTURE_CUBE_MAP; + glBindTexture(target, handle); + + int slice = 0; + for (int j = 0; j < 6; j++) + { + for (int i = 0; i < srcDesc.numMipLevels; i++) + { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i, internalFormat, srcDesc.size.width, srcDesc.size.height, 0, format, formatType, data[slice++]); + } + } + } + else + { + target = GL_TEXTURE_2D; + glBindTexture(target, handle); + for (int i = 0; i < srcDesc.numMipLevels; i++) + { + glTexImage2D(target, i, internalFormat, srcDesc.size.width, srcDesc.size.height, 0, format, formatType, data[i]); + } + } + } + break; + } + case Resource::Type::Texture3D: + { + target = GL_TEXTURE_3D; + glBindTexture(target, handle); + for (int i = 0; i < srcDesc.numMipLevels; i++) + { + glTexImage3D(target, i, internalFormat, srcDesc.size.width, srcDesc.size.height, srcDesc.size.depth, 0, format, formatType, data[i]); + } + break; + } + default: return nullptr; + } + + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT); + + // Assume regular sampling (might be superseded - if a combined sampler wanted) + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f); + + texture->m_target = target; + + return texture.detach(); +} + +static GLenum _calcUsage(Resource::Usage usage) +{ + typedef Resource::Usage Usage; + switch (usage) + { + case Usage::ConstantBuffer: return GL_DYNAMIC_DRAW; + default: return GL_STATIC_READ; + } +} + +static GLenum _calcTarget(Resource::Usage usage) +{ + typedef Resource::Usage Usage; + switch (usage) + { + case Usage::ConstantBuffer: return GL_UNIFORM_BUFFER; + default: return GL_SHADER_STORAGE_BUFFER; + } +} + +BufferResource* GLRenderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData) +{ + BufferResource::Desc desc(descIn); + + if (desc.bindFlags == 0) + { + desc.bindFlags = Resource::s_requiredBinding[int(initialUsage)]; + } + + const GLenum target = _calcTarget(initialUsage); + // TODO: should derive from desc... + const GLenum usage = _calcUsage(initialUsage); + GLuint bufferID = 0; glGenBuffers(1, &bufferID); glBindBuffer(target, bufferID); - glBufferData(target, desc.size, desc.initData, usage); + glBufferData(target, descIn.sizeInBytes, initData, usage); - return new BufferImpl(this, bufferID); + return new BufferResourceImpl(initialUsage, desc, this, bufferID, target); } InputLayout* GLRenderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) @@ -726,11 +849,11 @@ InputLayout* GLRenderer::createInputLayout(const InputElementDesc* inputElements return (InputLayout*)inputLayout; } -void* GLRenderer::map(Buffer* bufferIn, MapFlavor flavor) +void* GLRenderer::map(BufferResource* bufferIn, MapFlavor flavor) { - BufferImpl* buffer = static_cast<BufferImpl*>(bufferIn); + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn); - GLenum target = GL_UNIFORM_BUFFER; + //GLenum target = GL_UNIFORM_BUFFER; GLuint access = 0; switch (flavor) @@ -744,18 +867,15 @@ void* GLRenderer::map(Buffer* bufferIn, MapFlavor flavor) break; } - auto bufferID = buffer ? buffer->m_id : 0; - glBindBuffer(target, bufferID); + glBindBuffer(buffer->m_target, buffer->m_handle); - return glMapBuffer(target, access); + return glMapBuffer(buffer->m_target, access); } -void GLRenderer::unmap(Buffer* bufferIn) +void GLRenderer::unmap(BufferResource* bufferIn) { - BufferImpl* buffer = static_cast<BufferImpl*>(bufferIn); - GLenum target = GL_UNIFORM_BUFFER; - auto bufferID = buffer ? buffer->m_id : 0; - glUnmapBuffer(target); + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn); + glUnmapBuffer(buffer->m_target); } void GLRenderer::setInputLayout(InputLayout* inputLayout) @@ -777,14 +897,14 @@ void GLRenderer::setPrimitiveTopology(PrimitiveTopology topology) m_boundPrimitiveTopology = glTopology; } -void GLRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* strides, const UInt* offsets) +void GLRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) { for (UInt ii = 0; ii < slotCount; ++ii) { UInt slot = startSlot + ii; - BufferImpl* buffer = static_cast<BufferImpl*>(buffers[ii]); - GLuint bufferID = buffer ? buffer->m_id : 0; + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[ii]); + GLuint bufferID = buffer ? buffer->m_handle : 0; m_boundVertexStreamBuffers[slot] = bufferID; m_boundVertexStreamStrides[slot] = strides[ii]; @@ -800,7 +920,7 @@ void GLRenderer::setShaderProgram(ShaderProgram* programIn) glUseProgram(programID); } -void GLRenderer::setConstantBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* offsets) +void GLRenderer::setConstantBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets) { bindBufferImpl(GL_UNIFORM_BUFFER, startSlot, slotCount, buffers, offsets); } @@ -820,28 +940,51 @@ void GLRenderer::dispatchCompute(int x, int y, int z) BindingState* GLRenderer::createBindingState(const ShaderInputLayout& layout) { BindingStateImpl* state = new BindingStateImpl(this); - for (auto & entry : layout.entries) + for (auto & srcEntry : layout.entries) { - BindingEntry rsEntry; - rsEntry.isOutput = entry.isOutput; - rsEntry.binding = entry.glslBinding; - rsEntry.type = entry.type; - switch (entry.type) + BindingEntry dstEntry; + dstEntry.isOutput = srcEntry.isOutput; + dstEntry.binding = srcEntry.glslBinding; + dstEntry.type = srcEntry.type; + + switch (srcEntry.type) { case ShaderInputType::Buffer: - createInputBuffer(rsEntry, entry.bufferDesc, entry.bufferData); + { + 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: - createInputTexture(rsEntry, entry.textureDesc, InputSamplerDesc()); - break; case ShaderInputType::CombinedTextureSampler: - createInputTexture(rsEntry, entry.textureDesc, entry.samplerDesc); + { + RefPtr<TextureResource> textureResource; + + 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) + { + TextureResourceImpl* texture = static_cast<TextureResourceImpl*>(textureResource.Ptr()); + auto target = texture->m_target; + + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + } + break; + } case ShaderInputType::Sampler: - createInputSampler(rsEntry, entry.samplerDesc); + { + createInputSampler(dstEntry, srcEntry.samplerDesc); break; + } } - state->m_entries.Add(rsEntry); + state->m_entries.Add(dstEntry); } return state; } @@ -854,17 +997,28 @@ void GLRenderer::setBindingState(BindingState* stateIn) switch (entry.type) { case ShaderInputType::Buffer: - glBindBufferBase(entry.bindTarget, entry.binding[0], entry.handle); + { + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(entry.resource.Ptr()); + glBindBufferBase(buffer->m_target, entry.binding[0], buffer->m_handle); break; + } case ShaderInputType::Sampler: + { for (auto b : entry.binding) - glBindSampler(b, entry.handle); + { + glBindSampler(b, entry.samplerHandle); + } break; + } case ShaderInputType::Texture: case ShaderInputType::CombinedTextureSampler: + { + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(entry.resource.Ptr()); + glActiveTexture(GL_TEXTURE0 + entry.binding[0]); - glBindTexture(entry.bindTarget, entry.handle); + glBindTexture(buffer->m_target, buffer->m_handle); break; + } } } } @@ -878,11 +1032,19 @@ void GLRenderer::serializeOutput(BindingState* stateIn, const char* fileName) { if (entry.isOutput) { - glBindBuffer(entry.bindTarget, entry.handle); - auto ptr = (unsigned int *)glMapBuffer(entry.bindTarget, GL_READ_ONLY); - for (auto i = 0u; i < entry.bufferSize / sizeof(unsigned int); i++) - fprintf(f, "%X\n", ptr[i]); - glUnmapBuffer(entry.bindTarget); + 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); diff --git a/tools/render-test/render-test.vcxproj b/tools/render-test/render-test.vcxproj index 59ae16a14..2106bb9c2 100644 --- a/tools/render-test/render-test.vcxproj +++ b/tools/render-test/render-test.vcxproj @@ -175,6 +175,7 @@ <ClCompile Include="render-d3d12.cpp" /> <ClCompile Include="render-gl.cpp" /> <ClCompile Include="render-vk.cpp" /> + <ClCompile Include="render.cpp" /> <ClCompile Include="resource-d3d12.cpp" /> <ClCompile Include="shader-input-layout.cpp" /> <ClCompile Include="slang-support.cpp" /> diff --git a/tools/render-test/render-test.vcxproj.filters b/tools/render-test/render-test.vcxproj.filters index c0a24b015..640f132a2 100644 --- a/tools/render-test/render-test.vcxproj.filters +++ b/tools/render-test/render-test.vcxproj.filters @@ -51,6 +51,9 @@ <ClCompile Include="descriptor-heap-d3d12.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="render.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="options.h"> diff --git a/tools/render-test/render-vk.cpp b/tools/render-test/render-vk.cpp index 97da0bc40..13e67c132 100644 --- a/tools/render-test/render-vk.cpp +++ b/tools/render-test/render-vk.cpp @@ -89,20 +89,21 @@ public: virtual void setClearColor(const float color[4]) override; virtual void clearFrame() override; virtual void presentFrame() override; + 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 Buffer* createBuffer(const BufferDesc& desc) override; virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override; virtual BindingState * createBindingState(const ShaderInputLayout& layout) override; virtual ShaderCompiler* getShaderCompiler() override; - virtual void* map(Buffer* buffer, MapFlavor flavor) override; - virtual void unmap(Buffer* buffer) override; + virtual void* map(BufferResource* buffer, MapFlavor flavor) override; + virtual void unmap(BufferResource* buffer) override; virtual void setInputLayout(InputLayout* inputLayout) override; virtual void setPrimitiveTopology(PrimitiveTopology topology) override; virtual void setBindingState(BindingState* state); - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* strides, const UInt* offsets) override; + virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override; virtual void setShaderProgram(ShaderProgram* inProgram) override; - virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* offsets) override; + virtual void setConstantBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets) override; virtual void draw(UInt vertexCount, UInt startVertex) override; virtual void dispatchCompute(int x, int y, int z) override; virtual void submitGpuWork() override {} @@ -113,19 +114,22 @@ public: protected: - class BufferImpl: public Buffer + class BufferResourceImpl: public BufferResource { public: + typedef BufferResource Parent; - BufferImpl(VKRenderer* renderer, VkBuffer buffer, VkDeviceMemory memory): + BufferResourceImpl(Resource::Usage initialUsage, const BufferResource::Desc& desc, VKRenderer* renderer, VkBuffer buffer, VkDeviceMemory memory): + Parent(desc), m_renderer(renderer), m_buffer(buffer), - m_memory(memory) + m_memory(memory), + m_initialUsage(initialUsage) { assert(renderer); } - ~BufferImpl() + ~BufferResourceImpl() { // Now destroy the staging buffer if (m_renderer) @@ -135,6 +139,7 @@ public: } } + Resource::Usage m_initialUsage; VKRenderer* m_renderer; VkBuffer m_buffer; VkDeviceMemory m_memory; @@ -187,7 +192,7 @@ public: VkBool32 handleDebugMessage(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg); - BufferImpl* createBufferImpl(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, const void* initData = nullptr); + BufferResourceImpl* createBufferResourceImpl(Resource::Usage initialUsage, const BufferResource::Desc& desc, size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, const void* initData = nullptr); VkCommandBuffer getCommandBuffer(); VkCommandBuffer beginCommandBuffer(); @@ -315,7 +320,7 @@ void VKRenderer::flushCommandBuffer(VkCommandBuffer commandBuffer) vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer); } -VKRenderer::BufferImpl* VKRenderer::createBufferImpl(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, const void* initData) +VKRenderer::BufferResourceImpl* VKRenderer::createBufferResourceImpl(Resource::Usage initialUsage, const BufferResource::Desc& desc, size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, const void* initData) { if (initData) { @@ -352,7 +357,7 @@ VKRenderer::BufferImpl* VKRenderer::createBufferImpl(size_t bufferSize, VkBuffer // used for the buffer doesn't let us fill things in // directly. - RefPtr<BufferImpl> staging = createBufferImpl(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + 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); // Copy into staging buffer @@ -371,7 +376,7 @@ VKRenderer::BufferImpl* VKRenderer::createBufferImpl(size_t bufferSize, VkBuffer flushCommandBuffer(commandBuffer); } - return new BufferImpl(this, buffer, memory); + return new BufferResourceImpl(initialUsage, desc, this, buffer, memory); } uint32_t VKRenderer::getMemoryTypeIndex(uint32_t inTypeBits, VkMemoryPropertyFlags properties) @@ -413,19 +418,29 @@ void VKRenderer::createInputBuffer(const ShaderInputLayoutEntry& entry, const In 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) @@ -433,7 +448,7 @@ void VKRenderer::createInputBuffer(const ShaderInputLayoutEntry& entry, const In usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; } - RefPtr<BufferImpl> bufferImpl(createBufferImpl(bufferSize, usage, reqMemoryProperties, initData)); + 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. @@ -676,27 +691,80 @@ ShaderCompiler* VKRenderer::getShaderCompiler() return this; } -Buffer* VKRenderer::createBuffer(const BufferDesc& desc) +TextureResource* VKRenderer::createTextureResource(Resource::Type type, Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) { - size_t bufferSize = desc.size; + return nullptr; +} - VkBufferUsageFlags usage = 0; +static VkBufferUsageFlagBits _calcUsageFlagBit(Resource::BindFlag::Enum bind) +{ + typedef Resource::BindFlag BindFlag; + + switch (bind) + { + case BindFlag::VertexBuffer: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + case BindFlag::IndexBuffer: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + case BindFlag::ConstantBuffer: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + case BindFlag::StreamOutput: + case BindFlag::RenderTarget: + case BindFlag::DepthStencil: + { + assert(!"Not supported yet"); + return VkBufferUsageFlagBits(0); + } + case BindFlag::UnorderedAccess: return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + case BindFlag::PixelShaderResource: return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + case BindFlag::NonPixelShaderResource: return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + default: return VkBufferUsageFlagBits(0); + } +} + +static VkBufferUsageFlagBits _calcUsageFlagBit(int bindFlags) +{ + int dstFlags = 0; + while (bindFlags) + { + int lsb = bindFlags & -bindFlags; + dstFlags |= _calcUsageFlagBit(Resource::BindFlag::Enum(lsb)); + bindFlags &= ~lsb; + } + return VkBufferUsageFlagBits(dstFlags); +} + +BufferResource* VKRenderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData) +{ + BufferResource::Desc desc(descIn); + if (desc.bindFlags == 0) + { + desc.bindFlags = Resource::s_requiredBinding[int(initialUsage)]; + } + + const size_t bufferSize = desc.sizeInBytes; + + VkBufferUsageFlags usage = _calcUsageFlagBit(desc.bindFlags); VkMemoryPropertyFlags reqMemoryProperties = 0; - switch (desc.flavor) + if (desc.cpuAccessFlags & Resource::AccessFlag::Read) { - case BufferFlavor::Constant: - usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - reqMemoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - break; + // If it can be read from, set this + usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + } + if (desc.cpuAccessFlags & Resource::AccessFlag::Write) + { + usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + } - case BufferFlavor::Vertex: - usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - reqMemoryProperties = 0; + switch (initialUsage) + { + case Resource::Usage::ConstantBuffer: + { + reqMemoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; break; + } + default: break; } - return createBufferImpl(bufferSize, usage, reqMemoryProperties, desc.initData); + return createBufferResourceImpl(initialUsage, desc, bufferSize, usage, reqMemoryProperties, initData); } InputLayout* VKRenderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) @@ -708,12 +776,12 @@ InputLayout* VKRenderer::createInputLayout(const InputElementDesc* inputElements return (InputLayout*)impl; } -void* VKRenderer::map(Buffer* buffer, MapFlavor flavor) +void* VKRenderer::map(BufferResource* buffer, MapFlavor flavor) { return nullptr; } -void VKRenderer::unmap(Buffer* buffer) +void VKRenderer::unmap(BufferResource* buffer) { } @@ -725,7 +793,7 @@ void VKRenderer::setPrimitiveTopology(PrimitiveTopology topology) { } -void VKRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* strides, const UInt* offsets) +void VKRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) { } @@ -734,7 +802,7 @@ void VKRenderer::setShaderProgram(ShaderProgram* program) m_currentProgram = (ShaderProgramImpl*)program; } -void VKRenderer::setConstantBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* offsets) +void VKRenderer::setConstantBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets) { } @@ -800,9 +868,18 @@ void VKRenderer::serializeOutput(BindingState* s, const char* fileName) { if (bb.buffer) { - // create staging buffer + Resource::Usage initialUsage = Resource::Usage::NonPixelShaderResource; + BufferResource::Desc bufferResourceDesc; + size_t bufferSize = bb.bufferLength; - RefPtr<BufferImpl> staging(createBufferImpl(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, + + 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 diff --git a/tools/render-test/render.cpp b/tools/render-test/render.cpp new file mode 100644 index 000000000..292aa75f7 --- /dev/null +++ b/tools/render-test/render.cpp @@ -0,0 +1,203 @@ +// render.cpp +#include "render.h" + +#include "../../source/core/slang-math.h" + +namespace renderer_test { +using namespace Slang; + +/* static */const Resource::BindFlag::Enum Resource::s_requiredBinding[int(Usage::CountOf)] = +{ + BindFlag::VertexBuffer, // VertexBuffer + BindFlag::IndexBuffer, // IndexBuffer + BindFlag::ConstantBuffer, // ConstantBuffer + BindFlag::StreamOutput, // StreamOut + BindFlag::RenderTarget, // RenderTager + BindFlag::DepthStencil, // DepthRead + BindFlag::DepthStencil, // DepthWrite + BindFlag::UnorderedAccess, // UnorderedAccess + BindFlag::PixelShaderResource, // PixelShaderResource + BindFlag::NonPixelShaderResource, // NonPixelShaderResource + BindFlag::Enum(BindFlag::PixelShaderResource | BindFlag::NonPixelShaderResource), // GenericRead +}; + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!! TextureResource::Size !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +int TextureResource::Size::calcMaxDimension(Type type) const +{ + switch (type) + { + case Resource::Type::Texture1D: return this->width; + case Resource::Type::Texture3D: return std::max(std::max(this->width, this->height), this->depth); + case Resource::Type::TextureCube: // fallthru + case Resource::Type::Texture2D: + { + return std::max(this->width, this->height); + } + default: return 0; + } +} + +TextureResource::Size TextureResource::Size::calcMipSize(int mipLevel) const +{ + Size size; + size.width = TextureResource::calcMipSize(this->width, mipLevel); + size.height = TextureResource::calcMipSize(this->height, mipLevel); + size.depth = TextureResource::calcMipSize(this->depth, mipLevel); + return size; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!! BufferResource::Desc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +void BufferResource::Desc::setDefaults(Usage initialUsage) +{ + if (this->bindFlags == 0) + { + this->bindFlags = Resource::s_requiredBinding[int(initialUsage)]; + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!! TextureResource::Desc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +int TextureResource::Desc::calcNumMipLevels(Type type) const +{ + const int maxDimensionSize = this->size.calcMaxDimension(type); + return (maxDimensionSize > 0) ? (Math::Log2Floor(maxDimensionSize) + 1) : 0; +} + +int TextureResource::Desc::calcNumSubResources(Type type) const +{ + const int numMipMaps = (this->numMipLevels > 0) ? this->numMipLevels : calcNumMipLevels(type); + const int arrSize = (this->arraySize > 0) ? this->arraySize : 1; + + switch (type) + { + case Resource::Type::Texture1D: + case Resource::Type::Texture2D: + { + return numMipMaps * arrSize; + } + case Resource::Type::Texture3D: + { + // can't have arrays of 3d textures + assert(this->arraySize <= 1); + return numMipMaps * this->size.depth; + } + case Resource::Type::TextureCube: + { + // There are 6 faces to a cubemap + return numMipMaps * arrSize * 6; + } + default: return 0; + } +} + +void TextureResource::Desc::fixSize(Type type) +{ + switch (type) + { + case Resource::Type::Texture1D: + { + this->size.height = 1; + this->size.depth = 1; + break; + } + case Resource::Type::TextureCube: + case Resource::Type::Texture2D: + { + this->size.depth = 1; + break; + } + case Resource::Type::Texture3D: + { + // Can't have an array + this->arraySize = 0; + break; + } + default: break; + } +} + +void TextureResource::Desc::setDefaults(Type type, Usage initialUsage) +{ + fixSize(type); + if (this->bindFlags == 0) + { + this->bindFlags = Resource::s_requiredBinding[int(initialUsage)]; + } + if (this->numMipLevels <= 0) + { + this->numMipLevels = calcNumMipLevels(type); + } +} + +int TextureResource::Desc::calcEffectiveArraySize(Type type) const +{ + const int arrSize = (this->arraySize > 0) ? this->arraySize : 1; + + switch (type) + { + case Resource::Type::Texture1D: // fallthru + case Resource::Type::Texture2D: + { + return arrSize; + } + case Resource::Type::TextureCube: return arrSize * 6; + case Resource::Type::Texture3D: return 1; + default: return 0; + } +} + +void TextureResource::Desc::init() +{ + this->size.init(); + + this->format = Format::Unknown; + this->arraySize = 0; + this->numMipLevels = 0; + this->sampleDesc.init(); + + this->bindFlags = 0; + this->cpuAccessFlags = 0; +} + +void TextureResource::Desc::init1D(Format formatIn, int widthIn, int numMipMapsIn) +{ + this->size.init(widthIn); + + this->format = format; + this->arraySize = 0; + this->numMipLevels = numMipMapsIn; + this->sampleDesc.init(); + + this->bindFlags = 0; + this->cpuAccessFlags = 0; +} + +void TextureResource::Desc::init2D(Format formatIn, int widthIn, int heightIn, int numMipMapsIn) +{ + this->size.init(widthIn, heightIn); + + this->format = format; + this->arraySize = 0; + this->numMipLevels = numMipMapsIn; + this->sampleDesc.init(); + + this->bindFlags = 0; + this->cpuAccessFlags = 0; +} + +void TextureResource::Desc::init3D(Format formatIn, int widthIn, int heightIn, int depthIn, int numMipMapsIn) +{ + this->size.init(widthIn, heightIn, depthIn); + + this->format = format; + this->arraySize = 0; + this->numMipLevels = numMipMapsIn; + this->sampleDesc.init(); + + this->bindFlags = 0; + this->cpuAccessFlags = 0; +} + +} // renderer_test diff --git a/tools/render-test/render.h b/tools/render-test/render.h index 761f9e759..2800e069b 100644 --- a/tools/render-test/render.h +++ b/tools/render-test/render.h @@ -11,10 +11,6 @@ namespace renderer_test { // Declare opaque type -class Buffer: public Slang::RefObject -{ - public: -}; class InputLayout: public Slang::RefObject { public: @@ -71,19 +67,10 @@ enum class Format Unknown, RGB_Float32, RG_Float32, -}; + R_Float32, -enum class BufferFlavor -{ - Constant, - Vertex -}; - -struct BufferDesc -{ - UInt size = 0; - BufferFlavor flavor = BufferFlavor::Constant; - void const* initData = nullptr; + RGBA_Unorm_UInt8, + CountOf, }; struct InputElementDesc @@ -106,6 +93,231 @@ enum class PrimitiveTopology TriangleList, }; +class Resource: public Slang::RefObject +{ + public: + + /// The type of resource. + /// NOTE! The order needs to be such that all texture types are at or after Texture1D (otherwise isTexture won't work correctly) + enum class Type + { + Unknown, ///< Unknown + Buffer, ///< A buffer (like a constant/index/vertex buffer) + Texture1D, ///< A 1d texture + Texture2D, ///< A 2d texture + Texture3D, ///< A 3d texture + TextureCube, ///< A cubemap consists of 6 Texture2D like faces + CountOf, + }; + + /// Describes how a resource is to be used + enum class Usage + { + Unknown = -1, + VertexBuffer = 0, + IndexBuffer, + ConstantBuffer, + StreamOutput, + RenderTarget, + DepthRead, + DepthWrite, + UnorderedAccess, + PixelShaderResource, + NonPixelShaderResource, + GenericRead, + CountOf, + }; + + /// Binding flags describe all of the ways a resource can be bound - and therefore used + struct BindFlag + { + enum Enum + { + VertexBuffer = 0x001, + IndexBuffer = 0x002, + ConstantBuffer = 0x004, + StreamOutput = 0x008, + RenderTarget = 0x010, + DepthStencil = 0x020, + UnorderedAccess = 0x040, + PixelShaderResource = 0x080, + NonPixelShaderResource = 0x100, + }; + }; + + /// Combinations describe how a resource can be accessed (typically by the host/cpu) + struct AccessFlag + { + enum Enum + { + Read = 0x1, + Write = 0x2 + }; + }; + + /// Get the type + SLANG_FORCE_INLINE Type getType() const { return m_type; } + /// True if it's a texture derived type + SLANG_FORCE_INLINE bool isTexture() const { return int(m_type) >= int(Type::Texture1D); } + /// True if it's a buffer derived type + SLANG_FORCE_INLINE bool isBuffer() const { return m_type == Type::Buffer; } + + /// For a usage gives the required binding flags + static const BindFlag::Enum s_requiredBinding[int(Usage::CountOf)]; + + protected: + Resource(Type type): + m_type(type) + {} + + Type m_type; +}; + +class BufferResource: public Resource +{ + public: + typedef Resource Parent; + + struct Desc + { + 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 + }; + + /// Get the buffer description + SLANG_FORCE_INLINE const Desc& getDesc() const { return m_desc; } + + /// Ctor + BufferResource(const Desc& desc): + Parent(Type::Buffer), + m_desc(desc) + { + } + + protected: + Desc m_desc; +}; + +class TextureResource: public Resource +{ + public: + typedef Resource Parent; + + struct SampleDesc + { + void init() + { + numSamples = 1; + quality = 0; + } + int numSamples; ///< Number of samples per pixel + int quality; ///< The quality measure for the samples + }; + + struct Size + { + void init() + { + width = height = depth = 1; + } + void init(int widthIn, int heightIn = 1, int depthIn = 1) + { + width = widthIn; + height = heightIn; + depth = depthIn; + } + /// Given the type works out the maximum dimension size + int calcMaxDimension(Type type) const; + /// Given a size, calculates the size at a mip level + Size calcMipSize(int mipLevel) const; + + int width; ///< Width in pixels + int height; ///< Height in pixels (if 2d or 3d) + int depth; ///< Depth (if 3d) + }; + + struct Desc + { + /// Initialize with default values + void init(); + /// Initialize different dimensions. For cubemap, use init2D + void init1D(Format format, int width, int numMipMaps = 0); + void init2D(Format format, int width, int height, int numMipMaps = 0); + void init3D(Format format, int width, int height, int depth, int numMipMaps = 0); + + /// Given the type, calculates the number of mip maps. 0 on error + int calcNumMipLevels(Type type) const; + /// Calculate the total number of sub resources. 0 on error. + int calcNumSubResources(Type type) const; + + /// Calculate the effective array size - in essence the amount if mip map sets needed. + /// In practice takes into account if the arraySize is 0 (it's not an array, but it will still have at least one mip set) + /// and if the type is a cubemap (multiplies the amount of mip sets by 6) + int calcEffectiveArraySize(Type type) const; + + /// + void fixSize(Type type); + + /// 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 + + int numMipLevels; ///< Number of mip levels - if 0 will generate all mip levels + Format format; ///< The resources format + SampleDesc sampleDesc; ///< How the resource is sampled + }; + + /// The ordering of the subResources is + /// forall (cube faces (6) * arraySize / arraySize) + /// forall (mip levels) + /// forall (depth levels) + struct Data + { + ptrdiff_t* mipRowStrides; /// The row stride for a mip map + int numMips; ///< The number of mip maps + const void*const* subResources; ///< Pointers to each full mip subResource + int numSubResources; /// The total amount of subResources. Typically = numMips * depth * arraySize + }; + + /// Get the description of the texture + SLANG_FORCE_INLINE const Desc& getDesc() const { return m_desc; } + + /// Ctor + TextureResource(Type type, const Desc& desc): + Parent(type), + m_desc(desc) + { + } + + SLANG_FORCE_INLINE static int calcMipSize(int width, int mipLevel) + { + width = width >> mipLevel; + return width > 0 ? width : 1; + } + + protected: + Desc m_desc; +}; + class Renderer: public Slang::RefObject { public: @@ -116,28 +328,32 @@ public: virtual void presentFrame() = 0; + /// Create a texture resource. initData holds the initialize data to set the contents of the texture when constructed. + virtual TextureResource* createTextureResource(Resource::Type type, Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData = nullptr) { return nullptr; } + /// Create a buffer resource + 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 Buffer* createBuffer(const BufferDesc& desc) = 0; virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) = 0; virtual BindingState* createBindingState(const ShaderInputLayout& shaderInput) = 0; virtual ShaderCompiler* getShaderCompiler() = 0; - virtual void* map(Buffer* buffer, MapFlavor flavor) = 0; - virtual void unmap(Buffer* buffer) = 0; + virtual void* map(BufferResource* buffer, MapFlavor flavor) = 0; + virtual void unmap(BufferResource* buffer) = 0; virtual void setInputLayout(InputLayout* inputLayout) = 0; virtual void setPrimitiveTopology(PrimitiveTopology topology) = 0; virtual void setBindingState(BindingState* state) = 0; - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* strides, const UInt* offsets) = 0; + virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) = 0; - inline void setVertexBuffer(UInt slot, Buffer* buffer, UInt stride, UInt offset = 0); + inline void setVertexBuffer(UInt slot, BufferResource* buffer, UInt stride, UInt offset = 0); virtual void setShaderProgram(ShaderProgram* program) = 0; - virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* offsets) = 0; - inline void setConstantBuffer(UInt slot, Buffer* buffer, UInt offset = 0); + virtual void setConstantBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets) = 0; + inline void setConstantBuffer(UInt slot, BufferResource* buffer, UInt offset = 0); virtual void draw(UInt vertexCount, UInt startVertex = 0) = 0; virtual void dispatchCompute(int x, int y, int z) = 0; @@ -149,14 +365,13 @@ public: virtual void waitForGpu() = 0; }; - // ---------------------------------------------------------------------------------------- -inline void Renderer::setVertexBuffer(UInt slot, Buffer* buffer, UInt stride, UInt offset) +inline void Renderer::setVertexBuffer(UInt slot, BufferResource* buffer, UInt stride, UInt offset) { setVertexBuffers(slot, 1, &buffer, &stride, &offset); } // ---------------------------------------------------------------------------------------- -inline void Renderer::setConstantBuffer(UInt slot, Buffer* buffer, UInt offset) +inline void Renderer::setConstantBuffer(UInt slot, BufferResource* buffer, UInt offset) { setConstantBuffers(slot, 1, &buffer, &offset); } diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp index aa097bb44..d45ce55a4 100644 --- a/tools/render-test/slang-support.cpp +++ b/tools/render-test/slang-support.cpp @@ -172,5 +172,125 @@ ShaderCompiler* createSlangShaderCompiler( return result; } +SlangResult generateTextureResource(const InputTextureDesc& inputDesc, int bindFlags, Renderer* renderer, Slang::RefPtr<TextureResource>& textureOut) +{ + using namespace Slang; + + TextureData texData; + generateTextureData(texData, inputDesc); + + TextureResource::Desc textureResourceDesc; + textureResourceDesc.init(); + + textureResourceDesc.format = Format::RGBA_Unorm_UInt8; + textureResourceDesc.numMipLevels = texData.mipLevels; + textureResourceDesc.arraySize = inputDesc.arrayLength; + textureResourceDesc.bindFlags = bindFlags; + + // It's the same size in all dimensions + Resource::Type type = Resource::Type::Unknown; + switch (inputDesc.dimension) + { + case 1: + { + type = Resource::Type::Texture1D; + textureResourceDesc.size.init(inputDesc.size); + break; + } + case 2: + { + type = inputDesc.isCube ? Resource::Type::TextureCube : Resource::Type::Texture2D; + textureResourceDesc.size.init(inputDesc.size, inputDesc.size); + break; + } + case 3: + { + type = Resource::Type::Texture3D; + textureResourceDesc.size.init(inputDesc.size, inputDesc.size, inputDesc.size); + break; + } + } + + const int effectiveArraySize = textureResourceDesc.calcEffectiveArraySize(type); + const int numSubResources = textureResourceDesc.calcNumSubResources(type); + + Resource::Usage initialUsage = Resource::Usage::GenericRead; + TextureResource::Data initData; + + List<ptrdiff_t> mipRowStrides; + mipRowStrides.SetSize(textureResourceDesc.numMipLevels); + List<const void*> subResources; + subResources.SetSize(numSubResources); + + // Set up the src row strides + for (int i = 0; i < textureResourceDesc.numMipLevels; i++) + { + const int mipWidth = TextureResource::calcMipSize(textureResourceDesc.size.width, i); + mipRowStrides[i] = mipWidth * sizeof(uint32_t); + } + + // Set up pointers the the data + { + int subResourceIndex = 0; + const int numGen = int(texData.dataBuffer.Count()); + for (int i = 0; i < numSubResources; i++) + { + subResources[i] = texData.dataBuffer[subResourceIndex].Buffer(); + // Wrap around + subResourceIndex = (subResourceIndex + 1 >= numGen) ? 0 : (subResourceIndex + 1); + } + } + + initData.mipRowStrides = mipRowStrides.Buffer(); + initData.numMips = textureResourceDesc.numMipLevels; + initData.numSubResources = numSubResources; + initData.subResources = subResources.Buffer(); + + textureOut = renderer->createTextureResource(type, Resource::Usage::GenericRead, textureResourceDesc, &initData); + + return textureOut ? SLANG_OK : SLANG_FAIL; +} + +SlangResult createInputBufferResource(const InputBufferDesc& inputDesc, bool isOutput, size_t bufferSize, const void* initData, Renderer* renderer, Slang::RefPtr<BufferResource>& bufferOut) +{ + using namespace Slang; + + Resource::Usage initialUsage = Resource::Usage::GenericRead; + + BufferResource::Desc srcDesc; + srcDesc.init(bufferSize); + + int bindFlags = 0; + if (inputDesc.type == InputBufferType::ConstantBuffer) + { + bindFlags |= Resource::BindFlag::ConstantBuffer; + srcDesc.cpuAccessFlags |= Resource::AccessFlag::Write; + initialUsage = Resource::Usage::ConstantBuffer; + } + else + { + bindFlags |= Resource::BindFlag::UnorderedAccess | Resource::BindFlag::PixelShaderResource | Resource::BindFlag::NonPixelShaderResource; + srcDesc.elementSize = inputDesc.stride; + initialUsage = Resource::Usage::UnorderedAccess; + } + + if (isOutput) + { + srcDesc.cpuAccessFlags |= Resource::AccessFlag::Read; + } + + srcDesc.bindFlags = bindFlags; + + RefPtr<BufferResource> bufferResource = renderer->createBufferResource(initialUsage, srcDesc, initData); + if (!bufferResource) + { + return SLANG_FAIL; + } + + bufferOut = bufferResource; + return SLANG_OK; +} + + } // renderer_test diff --git a/tools/render-test/slang-support.h b/tools/render-test/slang-support.h index d2e32c52a..b5b56c295 100644 --- a/tools/render-test/slang-support.h +++ b/tools/render-test/slang-support.h @@ -5,6 +5,8 @@ #include <slang.h> +#include "shader-input-layout.h" + namespace renderer_test { ShaderCompiler* createSlangShaderCompiler( @@ -12,4 +14,10 @@ ShaderCompiler* createSlangShaderCompiler( SlangSourceLanguage sourceLanguage, SlangCompileTarget target); + /// Create the texture resource using the renderer +SlangResult generateTextureResource(const InputTextureDesc& inputDesc, int bindFlags, Renderer* renderer, Slang::RefPtr<TextureResource>& textureOut); + + /// 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); + } // renderer_test |
