diff --git a/src/backend/CMakeLists.txt b/src/backend/CMakeLists.txt index 53c41518d6..f55a9762af 100644 --- a/src/backend/CMakeLists.txt +++ b/src/backend/CMakeLists.txt @@ -243,6 +243,8 @@ if (WIN32) ${D3D12_DIR}/CommandAllocatorManager.h ${D3D12_DIR}/CommandBufferD3D12.cpp ${D3D12_DIR}/CommandBufferD3D12.h + ${D3D12_DIR}/DescriptorHeapAllocator.cpp + ${D3D12_DIR}/DescriptorHeapAllocator.h ${D3D12_DIR}/D3D12Backend.cpp ${D3D12_DIR}/D3D12Backend.h ${D3D12_DIR}/InputStateD3D12.cpp @@ -257,8 +259,12 @@ if (WIN32) ${D3D12_DIR}/ResourceAllocator.h ${D3D12_DIR}/ResourceUploader.cpp ${D3D12_DIR}/ResourceUploader.h + ${D3D12_DIR}/SamplerD3D12.cpp + ${D3D12_DIR}/SamplerD3D12.h ${D3D12_DIR}/ShaderModuleD3D12.cpp ${D3D12_DIR}/ShaderModuleD3D12.h + ${D3D12_DIR}/TextureD3D12.cpp + ${D3D12_DIR}/TextureD3D12.h ) endif() diff --git a/src/backend/common/CommandBuffer.cpp b/src/backend/common/CommandBuffer.cpp index 4ed0695b8f..fbfa4c72ba 100644 --- a/src/backend/common/CommandBuffer.cpp +++ b/src/backend/common/CommandBuffer.cpp @@ -218,6 +218,85 @@ namespace backend { commands->DataWasDestroyed(); } + void SkipCommand(CommandIterator* commands, Command type) { + switch (type) { + case Command::AdvanceSubpass: + commands->NextCommand(); + break; + + case Command::BeginRenderPass: + commands->NextCommand(); + break; + + case Command::CopyBufferToBuffer: + commands->NextCommand(); + break; + + case Command::CopyBufferToTexture: + commands->NextCommand(); + break; + + case Command::CopyTextureToBuffer: + commands->NextCommand(); + break; + + case Command::Dispatch: + commands->NextCommand(); + break; + + case Command::DrawArrays: + commands->NextCommand(); + break; + + case Command::DrawElements: + commands->NextCommand(); + break; + + case Command::EndRenderPass: + commands->NextCommand(); + break; + + case Command::SetPipeline: + commands->NextCommand(); + break; + + case Command::SetPushConstants: + { + auto* cmd = commands->NextCommand(); + commands->NextData(cmd->count); + } + break; + + case Command::SetStencilReference: + commands->NextCommand(); + break; + + case Command::SetBindGroup: + commands->NextCommand(); + break; + + case Command::SetIndexBuffer: + commands->NextCommand(); + break; + + case Command::SetVertexBuffers: + { + auto* cmd = commands->NextCommand(); + commands->NextData>(cmd->count); + commands->NextData(cmd->count); + } + break; + + case Command::TransitionBufferUsage: + commands->NextCommand(); + break; + + case Command::TransitionTextureUsage: + commands->NextCommand(); + break; + } + } + CommandBufferBuilder::CommandBufferBuilder(DeviceBase* device) : Builder(device), state(std::make_unique(this)) { } diff --git a/src/backend/common/Commands.h b/src/backend/common/Commands.h index 8ec86c2c5b..4ba48c38d5 100644 --- a/src/backend/common/Commands.h +++ b/src/backend/common/Commands.h @@ -151,6 +151,7 @@ namespace backend { // This needs to be called before the CommandIterator is freed so that the Ref<> present in // the commands have a chance to run their destructor and remove internal references. void FreeCommands(CommandIterator* commands); + void SkipCommand(CommandIterator* commands, Command type); } diff --git a/src/backend/d3d12/BufferD3D12.cpp b/src/backend/d3d12/BufferD3D12.cpp index aa580df577..6222516219 100644 --- a/src/backend/d3d12/BufferD3D12.cpp +++ b/src/backend/d3d12/BufferD3D12.cpp @@ -51,7 +51,7 @@ namespace d3d12 { D3D12_RESOURCE_DESC resourceDescriptor; resourceDescriptor.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; resourceDescriptor.Alignment = 0; - resourceDescriptor.Width = GetSize(); + resourceDescriptor.Width = GetD3D12Size(); resourceDescriptor.Height = 1; resourceDescriptor.DepthOrArraySize = 1; resourceDescriptor.MipLevels = 1; @@ -68,6 +68,11 @@ namespace d3d12 { device->GetResourceAllocator()->Release(resource); } + uint32_t Buffer::GetD3D12Size() const { + // TODO(enga@google.com): TODO investigate if this needs to be a constraint at the API level + return ((GetSize() + 256 - 1) / 256) * 256; // size is required to be 256-byte aligned. + } + ComPtr Buffer::GetD3D12Resource() { return resource; } @@ -113,5 +118,34 @@ namespace d3d12 { } } + + BufferView::BufferView(Device* device, BufferViewBuilder* builder) + : BufferViewBase(builder), device(device) { + + cbvDesc.BufferLocation = ToBackend(GetBuffer())->GetVA() + GetOffset(); + cbvDesc.SizeInBytes = GetD3D12Size(); + + uavDesc.Format = DXGI_FORMAT_UNKNOWN; + uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; + uavDesc.Buffer.FirstElement = GetOffset(); + uavDesc.Buffer.NumElements = GetD3D12Size(); + uavDesc.Buffer.StructureByteStride = 1; + uavDesc.Buffer.CounterOffsetInBytes = 0; + uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; + } + + uint32_t BufferView::GetD3D12Size() const { + // TODO(enga@google.com): TODO investigate if this needs to be a constraint at the API level + return ((GetSize() + 256 - 1) / 256) * 256; // size is required to be 256-byte aligned. + } + + const D3D12_CONSTANT_BUFFER_VIEW_DESC& BufferView::GetCBVDescriptor() const { + return cbvDesc; + } + + const D3D12_UNORDERED_ACCESS_VIEW_DESC& BufferView::GetUAVDescriptor() const { + return uavDesc; + } + } } diff --git a/src/backend/d3d12/BufferD3D12.h b/src/backend/d3d12/BufferD3D12.h index 44cbb64d67..7c106986d0 100644 --- a/src/backend/d3d12/BufferD3D12.h +++ b/src/backend/d3d12/BufferD3D12.h @@ -29,6 +29,7 @@ namespace d3d12 { Buffer(Device* device, BufferBuilder* builder); ~Buffer(); + uint32_t GetD3D12Size() const; ComPtr GetD3D12Resource(); D3D12_GPU_VIRTUAL_ADDRESS GetVA() const; bool GetResourceTransitionBarrier(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier); @@ -45,6 +46,20 @@ namespace d3d12 { }; + class BufferView : public BufferViewBase { + public: + BufferView(Device* device, BufferViewBuilder* builder); + + uint32_t GetD3D12Size() const; + const D3D12_CONSTANT_BUFFER_VIEW_DESC& GetCBVDescriptor() const; + const D3D12_UNORDERED_ACCESS_VIEW_DESC& GetUAVDescriptor() const; + + private: + Device* device; + D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc; + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc; + }; + } } diff --git a/src/backend/d3d12/CommandBufferD3D12.cpp b/src/backend/d3d12/CommandBufferD3D12.cpp index 17b38f892c..1d173bae2f 100644 --- a/src/backend/d3d12/CommandBufferD3D12.cpp +++ b/src/backend/d3d12/CommandBufferD3D12.cpp @@ -16,10 +16,13 @@ #include "common/Commands.h" #include "D3D12Backend.h" +#include "DescriptorHeapAllocator.h" #include "BufferD3D12.h" #include "InputStateD3D12.h" #include "PipelineD3D12.h" #include "PipelineLayoutD3D12.h" +#include "SamplerD3D12.h" +#include "TextureD3D12.h" namespace backend { namespace d3d12 { @@ -33,6 +36,146 @@ namespace d3d12 { return DXGI_FORMAT_R32_UINT; } } + + struct BindGroupStateTracker { + uint32_t cbvSrvUavDescriptorIndex = 0; + uint32_t samplerDescriptorIndex = 0; + DescriptorHeapHandle cbvSrvUavDescriptorHeap; + DescriptorHeapHandle samplerDescriptorHeap; + std::array bindGroups = {}; + Device* device; + + BindGroupStateTracker(Device* device) : device(device) { + } + + void TrackSetBindGroup(const BindGroupLayoutBase* bindGroupLayout) { + const auto& layout = bindGroupLayout->GetBindingInfo(); + + for (size_t binding = 0; binding < layout.mask.size(); ++binding) { + if (!layout.mask[binding]) { + continue; + } + + switch (layout.types[binding]) { + case nxt::BindingType::UniformBuffer: + case nxt::BindingType::StorageBuffer: + case nxt::BindingType::SampledTexture: + cbvSrvUavDescriptorIndex++; + case nxt::BindingType::Sampler: + samplerDescriptorIndex++; + } + } + } + + void SetBindGroup(Pipeline* pipeline, BindGroup* group, uint32_t index, ComPtr commandList) { + const auto& layout = group->GetLayout()->GetBindingInfo(); + + // these indices are the beginning of the descriptor table + uint32_t cbvSrvUavDescriptorStart = cbvSrvUavDescriptorIndex; + uint32_t samplerDescriptorStart = samplerDescriptorIndex; + + bindGroups[index] = group; + + PipelineLayout* pipelineLayout = ToBackend(pipeline->GetLayout()); + + // these indices are the offsets from the start of the descriptor table + uint32_t cbvIndex = pipelineLayout->GetDescriptorStartingIndex(index, PipelineLayout::Descriptor::Type::CBV); + uint32_t uavIndex = pipelineLayout->GetDescriptorStartingIndex(index, PipelineLayout::Descriptor::Type::UAV); + uint32_t srvIndex = pipelineLayout->GetDescriptorStartingIndex(index, PipelineLayout::Descriptor::Type::SRV); + uint32_t samplerIndex = pipelineLayout->GetDescriptorStartingIndex(index, PipelineLayout::Descriptor::Type::Sampler); + + for (size_t binding = 0; binding < layout.mask.size(); ++binding) { + if (!layout.mask[binding]) { + continue; + } + + switch (layout.types[binding]) { + case nxt::BindingType::UniformBuffer: + { + auto* view = ToBackend(group->GetBindingAsBufferView(binding)); + auto* buffer = ToBackend(view->GetBuffer()); + auto& cbvDesc = view->GetCBVDescriptor(); + device->GetD3D12Device()->CreateConstantBufferView(&cbvDesc, cbvSrvUavDescriptorHeap.GetCPUHandle(cbvSrvUavDescriptorStart + cbvIndex++)); + cbvSrvUavDescriptorIndex++; + } + break; + case nxt::BindingType::StorageBuffer: + { + auto* view = ToBackend(group->GetBindingAsBufferView(binding)); + auto* buffer = ToBackend(view->GetBuffer()); + auto& uavDesc = view->GetUAVDescriptor(); + device->GetD3D12Device()->CreateUnorderedAccessView(buffer->GetD3D12Resource().Get(), nullptr, &uavDesc, cbvSrvUavDescriptorHeap.GetCPUHandle(cbvSrvUavDescriptorStart + uavIndex++)); + cbvSrvUavDescriptorIndex++; + } + break; + case nxt::BindingType::SampledTexture: + { + auto* texture = ToBackend(group->GetBindingAsTextureView(binding)->GetTexture()); + auto& srvDesc = texture->GetSRVDescriptor(); + device->GetD3D12Device()->CreateShaderResourceView(texture->GetD3D12Resource().Get(), &srvDesc, cbvSrvUavDescriptorHeap.GetCPUHandle(cbvSrvUavDescriptorStart + srvIndex++)); + cbvSrvUavDescriptorIndex++; + } + break; + case nxt::BindingType::Sampler: + { + auto* sampler = ToBackend(group->GetBindingAsSampler(binding)); + auto& samplerDesc = sampler->GetSamplerDescriptor(); + device->GetD3D12Device()->CreateSampler(&samplerDesc, samplerDescriptorHeap.GetCPUHandle(samplerDescriptorStart + samplerIndex++)); + samplerDescriptorIndex++; + } + break; + } + } + + if (cbvSrvUavDescriptorStart != cbvSrvUavDescriptorIndex) { + uint32_t parameterIndex = pipelineLayout->GetCBVSRVUAVRootParameterIndex(index); + + if (pipeline->IsCompute()) { + commandList->SetComputeRootDescriptorTable(parameterIndex, cbvSrvUavDescriptorHeap.GetGPUHandle(cbvSrvUavDescriptorStart)); + } else { + commandList->SetGraphicsRootDescriptorTable(parameterIndex, cbvSrvUavDescriptorHeap.GetGPUHandle(cbvSrvUavDescriptorStart)); + } + } + + if (samplerDescriptorStart != samplerDescriptorIndex) { + uint32_t parameterIndex = pipelineLayout->GetSamplerRootParameterIndex(index); + + if (pipeline->IsCompute()) { + commandList->SetComputeRootDescriptorTable(parameterIndex, samplerDescriptorHeap.GetGPUHandle(samplerDescriptorStart)); + } else { + commandList->SetGraphicsRootDescriptorTable(parameterIndex, samplerDescriptorHeap.GetGPUHandle(samplerDescriptorStart)); + } + } + } + + void SetInheritedBindGroup(Pipeline* pipeline, uint32_t index, ComPtr commandList) { + BindGroup* group = bindGroups[index]; + ASSERT(group != nullptr); + SetBindGroup(pipeline, group, index, commandList); + } + + void AllocateAndSetDescriptorHeaps(Device* device, ComPtr commandList) { + cbvSrvUavDescriptorHeap = device->GetDescriptorHeapAllocator()->Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, cbvSrvUavDescriptorIndex); + samplerDescriptorHeap = device->GetDescriptorHeapAllocator()->Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, samplerDescriptorIndex); + + ID3D12DescriptorHeap* descriptorHeaps[2] = { cbvSrvUavDescriptorHeap.Get(), samplerDescriptorHeap.Get() }; + if (descriptorHeaps[0] && descriptorHeaps[1]) { + commandList->SetDescriptorHeaps(2, descriptorHeaps); + } else if (descriptorHeaps[0]) { + commandList->SetDescriptorHeaps(1, descriptorHeaps); + } else if (descriptorHeaps[1]) { + commandList->SetDescriptorHeaps(2, &descriptorHeaps[1]); + } + } + + void Reset() { + cbvSrvUavDescriptorIndex = 0; + samplerDescriptorIndex = 0; + for (uint32_t i = 0; i < kMaxBindGroups; ++i) { + bindGroups[i] = nullptr; + } + } + }; } CommandBuffer::CommandBuffer(Device* device, CommandBufferBuilder* builder) @@ -44,8 +187,59 @@ namespace d3d12 { } void CommandBuffer::FillCommands(ComPtr commandList) { + BindGroupStateTracker bindingTracker(device); + + { + Command type; + Pipeline* lastPipeline = nullptr; + PipelineLayout* lastLayout = nullptr; + + while(commands.NextCommandId(&type)) { + switch (type) { + case Command::SetPipeline: + { + SetPipelineCmd* cmd = commands.NextCommand(); + Pipeline* pipeline = ToBackend(cmd->pipeline).Get(); + PipelineLayout* layout = ToBackend(pipeline->GetLayout()); + + if (lastLayout) { + auto mask = layout->GetBindGroupsLayoutMask(); + for (uint32_t i = 0; i < kMaxBindGroups; ++i) { + // matching bind groups are inherited until they differ + if (mask[i] && lastLayout->GetBindGroupLayout(i) == layout->GetBindGroupLayout(i)) { + bindingTracker.TrackSetBindGroup(layout->GetBindGroupLayout(i)); + } else { + break; + } + } + } + + lastPipeline = pipeline; + lastLayout = layout; + } + break; + + case Command::SetBindGroup: + { + SetBindGroupCmd* cmd = commands.NextCommand(); + BindGroup* group = ToBackend(cmd->group.Get()); + bindingTracker.TrackSetBindGroup(group->GetLayout()); + } + break; + default: + SkipCommand(&commands, type); + } + } + + commands.Reset(); + } + + bindingTracker.AllocateAndSetDescriptorHeaps(device, commandList); + bindingTracker.Reset(); + Command type; Pipeline* lastPipeline = nullptr; + PipelineLayout* lastLayout = nullptr; RenderPass* currentRenderPass = nullptr; Framebuffer* currentFramebuffer = nullptr; @@ -64,10 +258,10 @@ namespace d3d12 { currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get()); currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get()); - float width = (float) currentFramebuffer->GetWidth(); - float height = (float) currentFramebuffer->GetHeight(); - D3D12_VIEWPORT viewport = { 0.f, 0.f, width, height, 0.f, 1.f }; - D3D12_RECT scissorRect = { 0.f, 0.f, width, height }; + uint32_t width = currentFramebuffer->GetWidth(); + uint32_t height = currentFramebuffer->GetHeight(); + D3D12_VIEWPORT viewport = { 0.f, 0.f, static_cast(width), static_cast(height), 0.f, 1.f }; + D3D12_RECT scissorRect = { 0, 0, static_cast(width), static_cast(height) }; commandList->RSSetViewports(1, &viewport); commandList->RSSetScissorRects(1, &scissorRect); commandList->OMSetRenderTargets(1, &device->GetCurrentRenderTargetDescriptor(), FALSE, nullptr); @@ -139,15 +333,33 @@ namespace d3d12 { case Command::SetPipeline: { SetPipelineCmd* cmd = commands.NextCommand(); - lastPipeline = ToBackend(cmd->pipeline).Get(); - PipelineLayout* pipelineLayout = ToBackend(lastPipeline->GetLayout()); + + Pipeline* pipeline = ToBackend(cmd->pipeline).Get(); + PipelineLayout* layout = ToBackend(pipeline->GetLayout()); // TODO - if (lastPipeline->IsCompute()) { - } else { - commandList->SetGraphicsRootSignature(pipelineLayout->GetRootSignature().Get()); - commandList->SetPipelineState(lastPipeline->GetRenderPipelineState().Get()); + if (pipeline->IsCompute()) { } + else { + commandList->SetGraphicsRootSignature(layout->GetRootSignature().Get()); + commandList->SetPipelineState(pipeline->GetRenderPipelineState().Get()); + } + + if (lastLayout) { + auto mask = layout->GetBindGroupsLayoutMask(); + for (uint32_t i = 0; i < kMaxBindGroups; ++i) { + // matching bind groups are inherited until they differ + if (mask[i] && lastLayout->GetBindGroupLayout(i) == layout->GetBindGroupLayout(i)) { + bindingTracker.SetInheritedBindGroup(pipeline, i, commandList); + } else { + break; + } + } + } + + + lastPipeline = pipeline; + lastLayout = layout; } break; @@ -166,6 +378,8 @@ namespace d3d12 { case Command::SetBindGroup: { SetBindGroupCmd* cmd = commands.NextCommand(); + BindGroup* group = ToBackend(cmd->group.Get()); + bindingTracker.SetBindGroup(lastPipeline, group, cmd->index, commandList); } break; @@ -224,6 +438,12 @@ namespace d3d12 { TransitionTextureUsageCmd* cmd = commands.NextCommand(); Texture* texture = ToBackend(cmd->texture.Get()); + + D3D12_RESOURCE_BARRIER barrier; + if (texture->GetResourceTransitionBarrier(texture->GetUsage(), cmd->usage, &barrier)) { + commandList->ResourceBarrier(1, &barrier); + } + texture->UpdateUsageInternal(cmd->usage); } break; diff --git a/src/backend/d3d12/D3D12Backend.cpp b/src/backend/d3d12/D3D12Backend.cpp index ad6fe58cbd..c1c2586e70 100644 --- a/src/backend/d3d12/D3D12Backend.cpp +++ b/src/backend/d3d12/D3D12Backend.cpp @@ -20,9 +20,12 @@ #include "PipelineD3D12.h" #include "PipelineLayoutD3D12.h" #include "QueueD3D12.h" +#include "SamplerD3D12.h" #include "ShaderModuleD3D12.h" +#include "TextureD3D12.h" #include "CommandAllocatorManager.h" +#include "DescriptorHeapAllocator.h" #include "ResourceAllocator.h" #include "ResourceUploader.h" @@ -80,6 +83,7 @@ namespace d3d12 { Device::Device(ComPtr d3d12Device) : d3d12Device(d3d12Device), commandAllocatorManager(new CommandAllocatorManager(this)), + descriptorHeapAllocator(new DescriptorHeapAllocator(this)), resourceAllocator(new ResourceAllocator(this)), resourceUploader(new ResourceUploader(this)) { @@ -104,6 +108,10 @@ namespace d3d12 { return commandQueue; } + DescriptorHeapAllocator* Device::GetDescriptorHeapAllocator() { + return descriptorHeapAllocator; + } + ResourceAllocator* Device::GetResourceAllocator() { return resourceAllocator; } @@ -142,6 +150,8 @@ namespace d3d12 { void Device::SetNextRenderTargetDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor) { this->renderTargetDescriptor = renderTargetDescriptor; + static const float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + GetPendingCommandList()->ClearRenderTargetView(renderTargetDescriptor, clearColor, 0, nullptr); } void Device::TickImpl() { @@ -149,6 +159,7 @@ namespace d3d12 { const uint64_t lastCompletedSerial = fence->GetCompletedValue(); resourceAllocator->FreeUnusedResources(lastCompletedSerial); commandAllocatorManager->ResetCompletedAllocators(lastCompletedSerial); + descriptorHeapAllocator->FreeDescriptorHeaps(lastCompletedSerial); } uint64_t Device::GetSerial() const { @@ -219,7 +230,7 @@ namespace d3d12 { return new RenderPass(this, builder); } SamplerBase* Device::CreateSampler(SamplerBuilder* builder) { - return new Sampler(this, builder); + return new Sampler(builder); } ShaderModuleBase* Device::CreateShaderModule(ShaderModuleBuilder* builder) { return new ShaderModule(this, builder); @@ -249,12 +260,6 @@ namespace d3d12 { : BindGroupLayoutBase(builder), device(device) { } - // BufferView - - BufferView::BufferView(Device* device, BufferViewBuilder* builder) - : BufferViewBase(builder), device(device) { - } - // DepthStencilState DepthStencilState::DepthStencilState(Device* device, DepthStencilStateBuilder* builder) @@ -273,26 +278,5 @@ namespace d3d12 { : RenderPassBase(builder), device(device) { } - // Sampler - - Sampler::Sampler(Device* device, SamplerBuilder* builder) - : SamplerBase(builder), device(device) { - } - - // Texture - - Texture::Texture(Device* device, TextureBuilder* builder) - : TextureBase(builder), device(device) { - } - - void Texture::TransitionUsageImpl(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage) { - } - - // TextureView - - TextureView::TextureView(Device* device, TextureViewBuilder* builder) - : TextureViewBase(builder), device(device) { - } - } } diff --git a/src/backend/d3d12/D3D12Backend.h b/src/backend/d3d12/D3D12Backend.h index 470851f2be..e76d0b9253 100644 --- a/src/backend/d3d12/D3D12Backend.h +++ b/src/backend/d3d12/D3D12Backend.h @@ -55,6 +55,7 @@ namespace d3d12 { class RenderPass; class CommandAllocatorManager; + class DescriptorHeapAllocator; class ResourceAllocator; class ResourceUploader; @@ -113,6 +114,7 @@ namespace d3d12 { ComPtr GetD3D12Device(); ComPtr GetCommandQueue(); + DescriptorHeapAllocator* GetDescriptorHeapAllocator(); ResourceAllocator* GetResourceAllocator(); ResourceUploader* GetResourceUploader(); @@ -141,6 +143,7 @@ namespace d3d12 { ComPtr commandQueue; CommandAllocatorManager* commandAllocatorManager; + DescriptorHeapAllocator* descriptorHeapAllocator; ResourceAllocator* resourceAllocator; ResourceUploader* resourceUploader; @@ -169,14 +172,6 @@ namespace d3d12 { Device* device; }; - class BufferView : public BufferViewBase { - public: - BufferView(Device* device, BufferViewBuilder* builder); - - private: - Device* device; - }; - class Framebuffer : public FramebufferBase { public: Framebuffer(Device* device, FramebufferBuilder* builder); @@ -201,32 +196,6 @@ namespace d3d12 { Device* device; }; - class Sampler : public SamplerBase { - public: - Sampler(Device* device, SamplerBuilder* builder); - - private: - Device* device; - }; - - class Texture : public TextureBase { - public: - Texture(Device* device, TextureBuilder* builder); - - private: - void TransitionUsageImpl(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage) override; - - Device* device; - }; - - class TextureView : public TextureViewBase { - public: - TextureView(Device* device, TextureViewBuilder* builder); - - private: - Device* device; - }; - } } diff --git a/src/backend/d3d12/DescriptorHeapAllocator.cpp b/src/backend/d3d12/DescriptorHeapAllocator.cpp new file mode 100644 index 0000000000..e38a65a953 --- /dev/null +++ b/src/backend/d3d12/DescriptorHeapAllocator.cpp @@ -0,0 +1,100 @@ +// Copyright 2017 The NXT Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "DescriptorHeapAllocator.h" + +#include "D3D12Backend.h" + +namespace backend { +namespace d3d12 { + + DescriptorHeapHandle::DescriptorHeapHandle() { + } + + DescriptorHeapHandle::DescriptorHeapHandle(ComPtr descriptorHeap, uint32_t sizeIncrement, uint32_t offset) + : device(device), descriptorHeap(descriptorHeap), sizeIncrement(sizeIncrement), offset(offset) { + } + + ID3D12DescriptorHeap* DescriptorHeapHandle::Get() const { + return descriptorHeap.Get(); + } + + D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapHandle::GetCPUHandle(uint32_t index) const { + ASSERT(descriptorHeap); + auto handle = descriptorHeap->GetCPUDescriptorHandleForHeapStart(); + handle.ptr += sizeIncrement * (index + offset); + return handle; + } + + D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapHandle::GetGPUHandle(uint32_t index) const { + ASSERT(descriptorHeap); + auto handle = descriptorHeap->GetGPUDescriptorHandleForHeapStart(); + handle.ptr += sizeIncrement * (index + offset); + return handle; + } + + + DescriptorHeapAllocator::DescriptorHeapAllocator(Device* device) + : device(device), + sizeIncrements { + device->GetD3D12Device()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV), + device->GetD3D12Device()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER), + device->GetD3D12Device()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV), + device->GetD3D12Device()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV), + } { + } + + DescriptorHeapHandle DescriptorHeapAllocator::Allocate(D3D12_DESCRIPTOR_HEAP_TYPE type, uint32_t count) { + if (count == 0) { + return DescriptorHeapHandle(); + } + + auto& pools = descriptorHeapPools[type]; + for (auto it : pools) { + auto& allocationInfo = it.second; + if (allocationInfo.remaining >= count) { + DescriptorHeapHandle handle(it.first, sizeIncrements[type], allocationInfo.size - allocationInfo.remaining); + allocationInfo.remaining -= count; + Release(handle); + return handle; + } + } + + ASSERT(count <= 2048); // TODO(enga@google.com): Have a very large CPU heap that's copied to GPU-visible heaps + uint32_t descriptorHeapSize = 2048; // TODO(enga@google.com): Allocate much more and use this as a pool + + D3D12_DESCRIPTOR_HEAP_DESC heapDescriptor; + heapDescriptor.Type = type; + heapDescriptor.NumDescriptors = descriptorHeapSize; + heapDescriptor.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + heapDescriptor.NodeMask = 0; + ComPtr heap; + ASSERT_SUCCESS(device->GetD3D12Device()->CreateDescriptorHeap(&heapDescriptor, IID_PPV_ARGS(&heap))); + AllocationInfo allocationInfo = { descriptorHeapSize, descriptorHeapSize - count }; + pools.emplace_back(std::make_pair(heap, allocationInfo)); + + DescriptorHeapHandle handle(heap, sizeIncrements[type], 0); + Release(handle); + return handle; + } + + void DescriptorHeapAllocator::FreeDescriptorHeaps(uint64_t lastCompletedSerial) { + releasedHandles.ClearUpTo(lastCompletedSerial); + } + + void DescriptorHeapAllocator::Release(DescriptorHeapHandle handle) { + releasedHandles.Enqueue(handle, device->GetSerial()); + } +} +} diff --git a/src/backend/d3d12/DescriptorHeapAllocator.h b/src/backend/d3d12/DescriptorHeapAllocator.h new file mode 100644 index 0000000000..07ac478d98 --- /dev/null +++ b/src/backend/d3d12/DescriptorHeapAllocator.h @@ -0,0 +1,76 @@ +// Copyright 2017 The NXT Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BACKEND_D3D12_DESCRIPTORHEAPALLOCATOR_H_ +#define BACKEND_D3D12_DESCRIPTORHEAPALLOCATOR_H_ + +#include "d3d12_platform.h" + +#include "common/SerialQueue.h" +#include +#include + +namespace backend { +namespace d3d12 { + + class Device; + + class DescriptorHeapHandle { + public: + DescriptorHeapHandle(); + DescriptorHeapHandle(ComPtr descriptorHeap, uint32_t sizeIncrement, uint32_t offset); + + ID3D12DescriptorHeap* Get() const; + D3D12_CPU_DESCRIPTOR_HANDLE GetCPUHandle(uint32_t index) const; + D3D12_GPU_DESCRIPTOR_HANDLE GetGPUHandle(uint32_t index) const; + + private: + Device* device; + ComPtr descriptorHeap; + uint32_t sizeIncrement; + uint32_t offset; + }; + + class DescriptorHeapAllocator { + public: + DescriptorHeapAllocator(Device* device); + + DescriptorHeapHandle Allocate(D3D12_DESCRIPTOR_HEAP_TYPE type, uint32_t count); + void FreeDescriptorHeaps(uint64_t lastCompletedSerial); + + private: + void Release(DescriptorHeapHandle handle); + + Device* device; + + static constexpr unsigned int kDescriptorHeapTypes = D3D12_DESCRIPTOR_HEAP_TYPE::D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; + + struct AllocationInfo { + uint32_t size; + uint32_t remaining; + }; + + using DescriptorHeapPool = std::pair, AllocationInfo>; + + using DescriptorHeapPoolList = std::vector; + + std::array sizeIncrements; + std::array descriptorHeapPools; + SerialQueue releasedHandles; + }; + +} +} + +#endif // BACKEND_D3D12_DESCRIPTORHEAPALLOCATOR_H_ diff --git a/src/backend/d3d12/GeneratedCodeIncludes.h b/src/backend/d3d12/GeneratedCodeIncludes.h index 0f776b9336..a4f6a83788 100644 --- a/src/backend/d3d12/GeneratedCodeIncludes.h +++ b/src/backend/d3d12/GeneratedCodeIncludes.h @@ -19,4 +19,6 @@ #include "PipelineD3D12.h" #include "PipelineLayoutD3D12.h" #include "QueueD3D12.h" +#include "SamplerD3D12.h" #include "ShaderModuleD3D12.h" +#include "TextureD3D12.h" diff --git a/src/backend/d3d12/PipelineD3D12.cpp b/src/backend/d3d12/PipelineD3D12.cpp index afcd3aef4a..290dd989d5 100644 --- a/src/backend/d3d12/PipelineD3D12.cpp +++ b/src/backend/d3d12/PipelineD3D12.cpp @@ -32,6 +32,8 @@ namespace d3d12 { // Enable better shader debugging with the graphics debugging tools. compileFlags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #endif + // SPRIV-cross does matrix multiplication expecting row major matrices + compileFlags |= D3DCOMPILE_PACK_MATRIX_ROW_MAJOR; if (IsCompute()) { const auto& module = ToBackend(builder->GetStageInfo(nxt::ShaderStage::Compute).module); @@ -54,7 +56,7 @@ namespace d3d12 { &compiledShader, &errors ))) { - printf("%s\n", errors->GetBufferPointer()); + printf("%s\n", reinterpret_cast(errors->GetBufferPointer())); ASSERT(false); } @@ -82,11 +84,11 @@ namespace d3d12 { switch (stage) { case nxt::ShaderStage::Vertex: shader = &descriptor.VS; - compileTarget = "vs_5_0"; + compileTarget = "vs_5_1"; break; case nxt::ShaderStage::Fragment: shader = &descriptor.PS; - compileTarget = "ps_5_0"; + compileTarget = "ps_5_1"; break; case nxt::ShaderStage::Compute: ASSERT(false); @@ -106,7 +108,7 @@ namespace d3d12 { &compiledShader[stage], &errors ))) { - printf("%s\n", errors->GetBufferPointer()); + printf("%s\n", reinterpret_cast(errors->GetBufferPointer())); ASSERT(false); } @@ -116,10 +118,15 @@ namespace d3d12 { } } - InputState* inputState = ToBackend(GetInputState()); - descriptor.InputLayout = inputState->GetD3D12InputLayoutDescriptor(); + PipelineLayout* layout = ToBackend(GetLayout()); - descriptor.pRootSignature = ToBackend(GetLayout())->GetRootSignature().Get(); + descriptor.pRootSignature = layout->GetRootSignature().Get(); + + // D3D12 logs warnings if any empty input state is used + InputState* inputState = ToBackend(GetInputState()); + if (inputState->GetAttributesSetMask().any()) { + descriptor.InputLayout = inputState->GetD3D12InputLayoutDescriptor(); + } descriptor.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; descriptor.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; diff --git a/src/backend/d3d12/PipelineLayoutD3D12.cpp b/src/backend/d3d12/PipelineLayoutD3D12.cpp index f5ba6c7531..bdf67ca4dc 100644 --- a/src/backend/d3d12/PipelineLayoutD3D12.cpp +++ b/src/backend/d3d12/PipelineLayoutD3D12.cpp @@ -15,6 +15,7 @@ #include "PipelineLayoutD3D12.h" #include "D3D12Backend.h" +#include "BindGroupLayoutD3D12.h" using Microsoft::WRL::ComPtr; @@ -24,10 +25,59 @@ namespace d3d12 { PipelineLayout::PipelineLayout(Device* device, PipelineLayoutBuilder* builder) : PipelineLayoutBase(builder), device(device) { - // Create an empty root signature. + D3D12_ROOT_PARAMETER rootParameters[kMaxBindGroups * 2]; + + // A root parameter is one of these types + union { + D3D12_ROOT_DESCRIPTOR_TABLE DescriptorTable; + D3D12_ROOT_CONSTANTS Constants; + D3D12_ROOT_DESCRIPTOR Descriptor; + } rootParameterValues[kMaxBindGroups * 2]; + // samplers must be in a separate descriptor table so we need at most twice as many tables as bind groups + + // Ranges are D3D12_DESCRIPTOR_RANGE_TYPE_(SRV|UAV|CBV|SAMPLER) + // They are grouped together so each bind group has at most 4 ranges + D3D12_DESCRIPTOR_RANGE ranges[kMaxBindGroups * 4]; + + uint32_t parameterIndex = 0; + uint32_t rangeIndex = 0; + + for (uint32_t group = 0; group < kMaxBindGroups; ++group) { + const BindGroupLayout* bindGroupLayout = ToBackend(GetBindGroupLayout(group)); + + // Set the root descriptor table parameter and copy ranges. Ranges are offset by the bind group index + // Returns whether or not the parameter was set. A root parameter is not set if the number of ranges is 0 + auto SetRootDescriptorTable = [&](uint32_t rangeCount, const D3D12_DESCRIPTOR_RANGE* descriptorRanges) -> bool { + if (rangeCount > 0) { + auto& rootParameter = rootParameters[parameterIndex]; + rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + rootParameter.DescriptorTable = rootParameterValues[parameterIndex].DescriptorTable; + rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + rootParameter.DescriptorTable.NumDescriptorRanges = rangeCount; + rootParameter.DescriptorTable.pDescriptorRanges = &ranges[rangeIndex]; + } + + for (uint32_t i = 0; i < rangeCount; ++i) { + ranges[rangeIndex] = descriptorRanges[i]; + ranges[rangeIndex].BaseShaderRegister = group * kMaxBindingsPerGroup; + rangeIndex++; + } + + return (rangeCount > 0); + }; + + if (SetRootDescriptorTable(bindGroupLayout->GetCbvUavSrvDescriptorTableSize(), bindGroupLayout->GetCbvUavSrvDescriptorRanges())) { + cbvUavSrvRootParameterInfo[group] = parameterIndex++; + } + + if (SetRootDescriptorTable(bindGroupLayout->GetSamplerDescriptorTableSize(), bindGroupLayout->GetSamplerDescriptorRanges())) { + samplerRootParameterInfo[group] = parameterIndex++; + } + } + D3D12_ROOT_SIGNATURE_DESC rootSignatureDescriptor; - rootSignatureDescriptor.NumParameters = 0; - rootSignatureDescriptor.pParameters = nullptr; + rootSignatureDescriptor.NumParameters = parameterIndex; + rootSignatureDescriptor.pParameters = rootParameters; rootSignatureDescriptor.NumStaticSamplers = 0; rootSignatureDescriptor.pStaticSamplers = nullptr; rootSignatureDescriptor.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; @@ -38,9 +88,19 @@ namespace d3d12 { ASSERT_SUCCESS(device->GetD3D12Device()->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&rootSignature))); } + + uint32_t PipelineLayout::GetCbvUavSrvRootParameterIndex(uint32_t group) const { + ASSERT(group < kMaxBindGroups); + return cbvUavSrvRootParameterInfo[group]; + } + + uint32_t PipelineLayout::GetSamplerRootParameterIndex(uint32_t group) const { + ASSERT(group < kMaxBindGroups); + return samplerRootParameterInfo[group]; + } + ComPtr PipelineLayout::GetRootSignature() { return rootSignature; } - } } diff --git a/src/backend/d3d12/PipelineLayoutD3D12.h b/src/backend/d3d12/PipelineLayoutD3D12.h index 57dd4ef36e..a8b24cd529 100644 --- a/src/backend/d3d12/PipelineLayoutD3D12.h +++ b/src/backend/d3d12/PipelineLayoutD3D12.h @@ -28,11 +28,35 @@ namespace d3d12 { public: PipelineLayout(Device* device, PipelineLayoutBuilder* builder); + class Descriptor { + public: + enum class Type { + CBV, + UAV, + SRV, + Sampler, + Count + }; + static constexpr unsigned int TypeCount = static_cast::type>(Type::Count); + }; + + uint32_t GetCbvUavSrvRootParameterIndex(uint32_t group) const; + uint32_t GetSamplerRootParameterIndex(uint32_t group) const; + ComPtr GetRootSignature(); private: + + static constexpr unsigned int ToIndex(Descriptor::Type type) { + return static_cast::type>(type); + } + Device* device; + std::array cbvUavSrvRootParameterInfo; + std::array samplerRootParameterInfo; + std::array, kMaxBindGroups> descriptorCountInfo; + ComPtr rootSignature; }; diff --git a/src/backend/d3d12/SamplerD3D12.cpp b/src/backend/d3d12/SamplerD3D12.cpp new file mode 100644 index 0000000000..b337b3947a --- /dev/null +++ b/src/backend/d3d12/SamplerD3D12.cpp @@ -0,0 +1,83 @@ +// Copyright 2017 The NXT Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "SamplerD3D12.h" + +#include "D3D12Backend.h" + +namespace backend { +namespace d3d12 { + + Sampler::Sampler(SamplerBuilder* builder) + : SamplerBase(builder) { + + // https://msdn.microsoft.com/en-us/library/windows/desktop/dn770367(v=vs.85).aspx + // D3D12_FILTER_MIN_MAG_MIP_POINT = 0 0 0 0 0 // hex value, decimal value, min linear, mag linear, mip linear + // D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR = 0x1 1 0 0 1 + // D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x4 4 0 1 0 + // D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR = 0x5 5 0 1 1 + // D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT = 0x10 16 1 0 0 + // D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x11 17 1 0 1 + // D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT = 0x14 20 1 1 0 + // D3D12_FILTER_MIN_MAG_MIP_LINEAR = 0x15 21 1 1 1 + + // if mip mode is linear, add 1 + // if mag mode is linear, add 4 + // if min mode is linear, add 16 + + uint8_t mode = 0; + + switch (builder->GetMinFilter()) { + case nxt::FilterMode::Nearest: + break; + case nxt::FilterMode::Linear: + mode += 16; + break; + } + + switch (builder->GetMagFilter()) { + case nxt::FilterMode::Nearest: + break; + case nxt::FilterMode::Linear: + mode += 4; + break; + } + + switch (builder->GetMipMapFilter()) { + case nxt::FilterMode::Nearest: + break; + case nxt::FilterMode::Linear: + mode += 1; + break; + } + + samplerDesc.Filter = static_cast(mode); + samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + samplerDesc.MipLODBias = 0.f; + samplerDesc.MaxAnisotropy = 1; + samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; + samplerDesc.BorderColor[0] = samplerDesc.BorderColor[1] = samplerDesc.BorderColor[2] = samplerDesc.BorderColor[3] = 0; + samplerDesc.MinLOD = 0; + samplerDesc.MaxLOD = D3D12_FLOAT32_MAX; + + } + + const D3D12_SAMPLER_DESC& Sampler::GetSamplerDescriptor() const { + return samplerDesc; + } + +} +} diff --git a/src/backend/d3d12/SamplerD3D12.h b/src/backend/d3d12/SamplerD3D12.h new file mode 100644 index 0000000000..87198b7319 --- /dev/null +++ b/src/backend/d3d12/SamplerD3D12.h @@ -0,0 +1,38 @@ +// Copyright 2017 The NXT Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BACKEND_D3D12_SAMPLERD3D12_H_ +#define BACKEND_D3D12_SAMPLERD3D12_H_ + +#include "common/Sampler.h" + +#include "d3d12_platform.h" + +namespace backend { +namespace d3d12 { + + class Sampler : public SamplerBase { + public: + Sampler(SamplerBuilder* builder); + + const D3D12_SAMPLER_DESC& GetSamplerDescriptor() const; + + private: + D3D12_SAMPLER_DESC samplerDesc; + }; + +} +} + +#endif // BACKEND_D3D12_SAMPLERD3D12_H_ diff --git a/src/backend/d3d12/ShaderModuleD3D12.cpp b/src/backend/d3d12/ShaderModuleD3D12.cpp index 44784989b7..54ed656609 100644 --- a/src/backend/d3d12/ShaderModuleD3D12.cpp +++ b/src/backend/d3d12/ShaderModuleD3D12.cpp @@ -24,7 +24,7 @@ namespace d3d12 { spirv_cross::CompilerHLSL compiler(builder->AcquireSpirv()); spirv_cross::CompilerHLSL::Options options; - options.shader_model = 40; + options.shader_model = 51; options.flip_vert_y = false; options.fixup_clipspace = true; @@ -32,7 +32,46 @@ namespace d3d12 { ExtractSpirvInfo(compiler); + enum RegisterType { + Buffer, + UnorderedAccess, + Texture, + Sampler, + Count, + }; + + std::array baseRegisters = {}; + + const auto& resources = compiler.get_shader_resources(); + + // rename bindings so that each register type b/u/t/s starts at 0 and then offset by kMaxBindingsPerGroup * bindGroupIndex + auto RenumberBindings = [&](std::vector resources, uint32_t offset) { + for (const auto& resource : resources) { + auto bindGroupIndex = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet); + auto& baseRegister = baseRegisters[RegisterType::Count * bindGroupIndex + offset]; + auto bindGroupOffset = bindGroupIndex * kMaxBindingsPerGroup; + compiler.set_decoration(resource.id, spv::DecorationBinding, bindGroupOffset + baseRegister++); + } + }; + + RenumberBindings(resources.uniform_buffers, RegisterType::Buffer); + RenumberBindings(resources.storage_buffers, RegisterType::UnorderedAccess); + RenumberBindings(resources.separate_images, RegisterType::Texture); + RenumberBindings(resources.separate_samplers, RegisterType::Sampler); + hlslSource = compiler.compile(); + + { + // pending https://github.com/KhronosGroup/SPIRV-Cross/issues/216 + // rename ": register(cN)" to ": register(bN)" + std::string::size_type pos = 0; + const std::string search = ": register(c"; + const std::string replace = ": register(b"; + while ((pos = hlslSource.find(search, pos)) != std::string::npos) { + hlslSource.replace(pos, search.length(), replace); + pos += replace.length(); + } + } } const std::string& ShaderModule::GetHLSLSource() const { diff --git a/src/backend/d3d12/TextureD3D12.cpp b/src/backend/d3d12/TextureD3D12.cpp new file mode 100644 index 0000000000..3aaf2c0687 --- /dev/null +++ b/src/backend/d3d12/TextureD3D12.cpp @@ -0,0 +1,153 @@ +// Copyright 2017 The NXT Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "TextureD3D12.h" + +#include "D3D12Backend.h" +#include "ResourceAllocator.h" + +namespace backend { +namespace d3d12 { + + namespace { + D3D12_RESOURCE_STATES D3D12TextureUsage(nxt::TextureUsageBit usage) { + D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_COMMON; + + if (usage & nxt::TextureUsageBit::TransferSrc) { + resourceState |= D3D12_RESOURCE_STATE_COPY_SOURCE; + } + if (usage & nxt::TextureUsageBit::TransferDst) { + resourceState |= D3D12_RESOURCE_STATE_COPY_DEST; + } + if (usage & nxt::TextureUsageBit::Sampled) { + resourceState |= (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + } + if (usage & nxt::TextureUsageBit::Storage) { + resourceState |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + } + if (usage & nxt::TextureUsageBit::ColorAttachment) { + resourceState |= D3D12_RESOURCE_STATE_RENDER_TARGET; + } + if (usage & nxt::TextureUsageBit::DepthStencilAttachment) { + resourceState |= D3D12_RESOURCE_STATE_DEPTH_WRITE; + } + + return resourceState; + } + + D3D12_RESOURCE_FLAGS D3D12ResourceFlags(nxt::TextureUsageBit usage) { + D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE; + + if (usage & nxt::TextureUsageBit::Storage) { + flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + } + if (usage & nxt::TextureUsageBit::ColorAttachment) { + flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + } + if (usage & nxt::TextureUsageBit::DepthStencilAttachment) { + flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + } + + return flags; + } + + D3D12_RESOURCE_DIMENSION D3D12TextureDimension(nxt::TextureDimension dimension) { + switch (dimension) { + case nxt::TextureDimension::e2D: + return D3D12_RESOURCE_DIMENSION_TEXTURE2D; + } + } + + DXGI_FORMAT D3D12TextureFormat(nxt::TextureFormat format) { + switch (format) { + case nxt::TextureFormat::R8G8B8A8Unorm: + return DXGI_FORMAT_R8G8B8A8_UNORM; + } + } + } + + Texture::Texture(Device* device, TextureBuilder* builder) + : TextureBase(builder), device(device) { + + D3D12_RESOURCE_DESC resourceDescriptor; + resourceDescriptor.Dimension = D3D12TextureDimension(GetDimension()); + resourceDescriptor.Alignment = 0; + resourceDescriptor.Width = GetWidth(); + resourceDescriptor.Height = GetHeight(); + resourceDescriptor.DepthOrArraySize = GetDepth(); + resourceDescriptor.MipLevels = GetNumMipLevels(); + resourceDescriptor.Format = D3D12TextureFormat(GetFormat()); + resourceDescriptor.SampleDesc.Count = 1; + resourceDescriptor.SampleDesc.Quality = 0; + resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + resourceDescriptor.Flags = D3D12ResourceFlags(GetUsage()); + + resource = device->GetResourceAllocator()->Allocate(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor, D3D12TextureUsage(GetUsage())); + } + + Texture::~Texture() { + device->GetResourceAllocator()->Release(resource); + } + + ComPtr Texture::GetD3D12Resource() { + return resource; + } + + bool Texture::GetResourceTransitionBarrier(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier) { + D3D12_RESOURCE_STATES stateBefore = D3D12TextureUsage(currentUsage); + D3D12_RESOURCE_STATES stateAfter = D3D12TextureUsage(targetUsage); + + if (stateBefore == stateAfter) { + return false; + } + + barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier->Transition.pResource = resource.Get(); + barrier->Transition.StateBefore = stateBefore; + barrier->Transition.StateAfter = stateAfter; + barrier->Transition.Subresource = 0; + + return true; + } + + void Texture::TransitionUsageImpl(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage) { + D3D12_RESOURCE_BARRIER barrier; + if (GetResourceTransitionBarrier(currentUsage, targetUsage, &barrier)) { + device->GetPendingCommandList()->ResourceBarrier(1, &barrier); + } + } + + TextureView::TextureView(Device* device, TextureViewBuilder* builder) + : TextureViewBase(builder) { + + srvDesc.Format = D3D12TextureFormat(GetTexture()->GetFormat()); + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + switch (GetTexture()->GetDimension()) { + case nxt::TextureDimension::e2D: + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Texture2D.MipLevels = GetTexture()->GetNumMipLevels(); + srvDesc.Texture2D.PlaneSlice = 0; + srvDesc.Texture2D.ResourceMinLODClamp = 0; + break; + } + } + + const D3D12_SHADER_RESOURCE_VIEW_DESC& TextureView::GetSRVDescriptor() const { + return srvDesc; + } + +} +} diff --git a/src/backend/d3d12/TextureD3D12.h b/src/backend/d3d12/TextureD3D12.h new file mode 100644 index 0000000000..110a353d2f --- /dev/null +++ b/src/backend/d3d12/TextureD3D12.h @@ -0,0 +1,56 @@ +// Copyright 2017 The NXT Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BACKEND_D3D12_TEXTURED3D12_H_ +#define BACKEND_D3D12_TEXTURED3D12_H_ + +#include "common/Texture.h" + +#include "d3d12_platform.h" + +namespace backend { +namespace d3d12 { + + class Device; + + class Texture : public TextureBase { + public: + Texture(Device* device, TextureBuilder* builder); + ~Texture(); + + ComPtr GetD3D12Resource(); + bool GetResourceTransitionBarrier(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier); + + private: + Device* device; + ComPtr resource; + + // NXT API + void TransitionUsageImpl(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage) override; + }; + + class TextureView : public TextureViewBase { + public: + TextureView(Device* device, TextureViewBuilder* builder); + + const D3D12_SHADER_RESOURCE_VIEW_DESC& GetSRVDescriptor() const; + + private: + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; + }; + +} +} + +#endif // BACKEND_D3D12_TEXTURED3D12_H_