Add D3D12 buffer, texture, and sampler binding

This commit is contained in:
Austin Eng 2017-06-16 14:26:26 -04:00 committed by Austin Eng
parent 29477375a6
commit aecf0b130e
19 changed files with 1031 additions and 85 deletions

View File

@ -243,6 +243,8 @@ if (WIN32)
${D3D12_DIR}/CommandAllocatorManager.h ${D3D12_DIR}/CommandAllocatorManager.h
${D3D12_DIR}/CommandBufferD3D12.cpp ${D3D12_DIR}/CommandBufferD3D12.cpp
${D3D12_DIR}/CommandBufferD3D12.h ${D3D12_DIR}/CommandBufferD3D12.h
${D3D12_DIR}/DescriptorHeapAllocator.cpp
${D3D12_DIR}/DescriptorHeapAllocator.h
${D3D12_DIR}/D3D12Backend.cpp ${D3D12_DIR}/D3D12Backend.cpp
${D3D12_DIR}/D3D12Backend.h ${D3D12_DIR}/D3D12Backend.h
${D3D12_DIR}/InputStateD3D12.cpp ${D3D12_DIR}/InputStateD3D12.cpp
@ -257,8 +259,12 @@ if (WIN32)
${D3D12_DIR}/ResourceAllocator.h ${D3D12_DIR}/ResourceAllocator.h
${D3D12_DIR}/ResourceUploader.cpp ${D3D12_DIR}/ResourceUploader.cpp
${D3D12_DIR}/ResourceUploader.h ${D3D12_DIR}/ResourceUploader.h
${D3D12_DIR}/SamplerD3D12.cpp
${D3D12_DIR}/SamplerD3D12.h
${D3D12_DIR}/ShaderModuleD3D12.cpp ${D3D12_DIR}/ShaderModuleD3D12.cpp
${D3D12_DIR}/ShaderModuleD3D12.h ${D3D12_DIR}/ShaderModuleD3D12.h
${D3D12_DIR}/TextureD3D12.cpp
${D3D12_DIR}/TextureD3D12.h
) )
endif() endif()

View File

@ -218,6 +218,85 @@ namespace backend {
commands->DataWasDestroyed(); commands->DataWasDestroyed();
} }
void SkipCommand(CommandIterator* commands, Command type) {
switch (type) {
case Command::AdvanceSubpass:
commands->NextCommand<AdvanceSubpassCmd>();
break;
case Command::BeginRenderPass:
commands->NextCommand<BeginRenderPassCmd>();
break;
case Command::CopyBufferToBuffer:
commands->NextCommand<CopyBufferToBufferCmd>();
break;
case Command::CopyBufferToTexture:
commands->NextCommand<CopyBufferToTextureCmd>();
break;
case Command::CopyTextureToBuffer:
commands->NextCommand<CopyTextureToBufferCmd>();
break;
case Command::Dispatch:
commands->NextCommand<DispatchCmd>();
break;
case Command::DrawArrays:
commands->NextCommand<DrawArraysCmd>();
break;
case Command::DrawElements:
commands->NextCommand<DrawElementsCmd>();
break;
case Command::EndRenderPass:
commands->NextCommand<EndRenderPassCmd>();
break;
case Command::SetPipeline:
commands->NextCommand<SetPipelineCmd>();
break;
case Command::SetPushConstants:
{
auto* cmd = commands->NextCommand<SetPushConstantsCmd>();
commands->NextData<uint32_t>(cmd->count);
}
break;
case Command::SetStencilReference:
commands->NextCommand<SetStencilReferenceCmd>();
break;
case Command::SetBindGroup:
commands->NextCommand<SetBindGroupCmd>();
break;
case Command::SetIndexBuffer:
commands->NextCommand<SetIndexBufferCmd>();
break;
case Command::SetVertexBuffers:
{
auto* cmd = commands->NextCommand<SetVertexBuffersCmd>();
commands->NextData<Ref<BufferBase>>(cmd->count);
commands->NextData<uint32_t>(cmd->count);
}
break;
case Command::TransitionBufferUsage:
commands->NextCommand<TransitionBufferUsageCmd>();
break;
case Command::TransitionTextureUsage:
commands->NextCommand<TransitionTextureUsageCmd>();
break;
}
}
CommandBufferBuilder::CommandBufferBuilder(DeviceBase* device) : Builder(device), state(std::make_unique<CommandBufferStateTracker>(this)) { CommandBufferBuilder::CommandBufferBuilder(DeviceBase* device) : Builder(device), state(std::make_unique<CommandBufferStateTracker>(this)) {
} }

View File

@ -151,6 +151,7 @@ namespace backend {
// This needs to be called before the CommandIterator is freed so that the Ref<> present in // 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. // the commands have a chance to run their destructor and remove internal references.
void FreeCommands(CommandIterator* commands); void FreeCommands(CommandIterator* commands);
void SkipCommand(CommandIterator* commands, Command type);
} }

View File

@ -51,7 +51,7 @@ namespace d3d12 {
D3D12_RESOURCE_DESC resourceDescriptor; D3D12_RESOURCE_DESC resourceDescriptor;
resourceDescriptor.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; resourceDescriptor.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
resourceDescriptor.Alignment = 0; resourceDescriptor.Alignment = 0;
resourceDescriptor.Width = GetSize(); resourceDescriptor.Width = GetD3D12Size();
resourceDescriptor.Height = 1; resourceDescriptor.Height = 1;
resourceDescriptor.DepthOrArraySize = 1; resourceDescriptor.DepthOrArraySize = 1;
resourceDescriptor.MipLevels = 1; resourceDescriptor.MipLevels = 1;
@ -68,6 +68,11 @@ namespace d3d12 {
device->GetResourceAllocator()->Release(resource); 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<ID3D12Resource> Buffer::GetD3D12Resource() { ComPtr<ID3D12Resource> Buffer::GetD3D12Resource() {
return resource; 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;
}
} }
} }

View File

@ -29,6 +29,7 @@ namespace d3d12 {
Buffer(Device* device, BufferBuilder* builder); Buffer(Device* device, BufferBuilder* builder);
~Buffer(); ~Buffer();
uint32_t GetD3D12Size() const;
ComPtr<ID3D12Resource> GetD3D12Resource(); ComPtr<ID3D12Resource> GetD3D12Resource();
D3D12_GPU_VIRTUAL_ADDRESS GetVA() const; D3D12_GPU_VIRTUAL_ADDRESS GetVA() const;
bool GetResourceTransitionBarrier(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier); 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;
};
} }
} }

View File

@ -16,10 +16,13 @@
#include "common/Commands.h" #include "common/Commands.h"
#include "D3D12Backend.h" #include "D3D12Backend.h"
#include "DescriptorHeapAllocator.h"
#include "BufferD3D12.h" #include "BufferD3D12.h"
#include "InputStateD3D12.h" #include "InputStateD3D12.h"
#include "PipelineD3D12.h" #include "PipelineD3D12.h"
#include "PipelineLayoutD3D12.h" #include "PipelineLayoutD3D12.h"
#include "SamplerD3D12.h"
#include "TextureD3D12.h"
namespace backend { namespace backend {
namespace d3d12 { namespace d3d12 {
@ -33,6 +36,146 @@ namespace d3d12 {
return DXGI_FORMAT_R32_UINT; return DXGI_FORMAT_R32_UINT;
} }
} }
struct BindGroupStateTracker {
uint32_t cbvSrvUavDescriptorIndex = 0;
uint32_t samplerDescriptorIndex = 0;
DescriptorHeapHandle cbvSrvUavDescriptorHeap;
DescriptorHeapHandle samplerDescriptorHeap;
std::array<BindGroup*, kMaxBindGroups> 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<ID3D12GraphicsCommandList> 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<ID3D12GraphicsCommandList> commandList) {
BindGroup* group = bindGroups[index];
ASSERT(group != nullptr);
SetBindGroup(pipeline, group, index, commandList);
}
void AllocateAndSetDescriptorHeaps(Device* device, ComPtr<ID3D12GraphicsCommandList> 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) CommandBuffer::CommandBuffer(Device* device, CommandBufferBuilder* builder)
@ -44,8 +187,59 @@ namespace d3d12 {
} }
void CommandBuffer::FillCommands(ComPtr<ID3D12GraphicsCommandList> commandList) { void CommandBuffer::FillCommands(ComPtr<ID3D12GraphicsCommandList> commandList) {
BindGroupStateTracker bindingTracker(device);
{
Command type; Command type;
Pipeline* lastPipeline = nullptr; Pipeline* lastPipeline = nullptr;
PipelineLayout* lastLayout = nullptr;
while(commands.NextCommandId(&type)) {
switch (type) {
case Command::SetPipeline:
{
SetPipelineCmd* cmd = commands.NextCommand<SetPipelineCmd>();
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<SetBindGroupCmd>();
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; RenderPass* currentRenderPass = nullptr;
Framebuffer* currentFramebuffer = nullptr; Framebuffer* currentFramebuffer = nullptr;
@ -64,10 +258,10 @@ namespace d3d12 {
currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get()); currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get());
currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get()); currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get());
float width = (float) currentFramebuffer->GetWidth(); uint32_t width = currentFramebuffer->GetWidth();
float height = (float) currentFramebuffer->GetHeight(); uint32_t height = currentFramebuffer->GetHeight();
D3D12_VIEWPORT viewport = { 0.f, 0.f, width, height, 0.f, 1.f }; D3D12_VIEWPORT viewport = { 0.f, 0.f, static_cast<float>(width), static_cast<float>(height), 0.f, 1.f };
D3D12_RECT scissorRect = { 0.f, 0.f, width, height }; D3D12_RECT scissorRect = { 0, 0, static_cast<long>(width), static_cast<long>(height) };
commandList->RSSetViewports(1, &viewport); commandList->RSSetViewports(1, &viewport);
commandList->RSSetScissorRects(1, &scissorRect); commandList->RSSetScissorRects(1, &scissorRect);
commandList->OMSetRenderTargets(1, &device->GetCurrentRenderTargetDescriptor(), FALSE, nullptr); commandList->OMSetRenderTargets(1, &device->GetCurrentRenderTargetDescriptor(), FALSE, nullptr);
@ -139,15 +333,33 @@ namespace d3d12 {
case Command::SetPipeline: case Command::SetPipeline:
{ {
SetPipelineCmd* cmd = commands.NextCommand<SetPipelineCmd>(); SetPipelineCmd* cmd = commands.NextCommand<SetPipelineCmd>();
lastPipeline = ToBackend(cmd->pipeline).Get();
PipelineLayout* pipelineLayout = ToBackend(lastPipeline->GetLayout()); Pipeline* pipeline = ToBackend(cmd->pipeline).Get();
PipelineLayout* layout = ToBackend(pipeline->GetLayout());
// TODO // TODO
if (lastPipeline->IsCompute()) { if (pipeline->IsCompute()) {
} else {
commandList->SetGraphicsRootSignature(pipelineLayout->GetRootSignature().Get());
commandList->SetPipelineState(lastPipeline->GetRenderPipelineState().Get());
} }
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; break;
@ -166,6 +378,8 @@ namespace d3d12 {
case Command::SetBindGroup: case Command::SetBindGroup:
{ {
SetBindGroupCmd* cmd = commands.NextCommand<SetBindGroupCmd>(); SetBindGroupCmd* cmd = commands.NextCommand<SetBindGroupCmd>();
BindGroup* group = ToBackend(cmd->group.Get());
bindingTracker.SetBindGroup(lastPipeline, group, cmd->index, commandList);
} }
break; break;
@ -224,6 +438,12 @@ namespace d3d12 {
TransitionTextureUsageCmd* cmd = commands.NextCommand<TransitionTextureUsageCmd>(); TransitionTextureUsageCmd* cmd = commands.NextCommand<TransitionTextureUsageCmd>();
Texture* texture = ToBackend(cmd->texture.Get()); 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); texture->UpdateUsageInternal(cmd->usage);
} }
break; break;

View File

@ -20,9 +20,12 @@
#include "PipelineD3D12.h" #include "PipelineD3D12.h"
#include "PipelineLayoutD3D12.h" #include "PipelineLayoutD3D12.h"
#include "QueueD3D12.h" #include "QueueD3D12.h"
#include "SamplerD3D12.h"
#include "ShaderModuleD3D12.h" #include "ShaderModuleD3D12.h"
#include "TextureD3D12.h"
#include "CommandAllocatorManager.h" #include "CommandAllocatorManager.h"
#include "DescriptorHeapAllocator.h"
#include "ResourceAllocator.h" #include "ResourceAllocator.h"
#include "ResourceUploader.h" #include "ResourceUploader.h"
@ -80,6 +83,7 @@ namespace d3d12 {
Device::Device(ComPtr<ID3D12Device> d3d12Device) Device::Device(ComPtr<ID3D12Device> d3d12Device)
: d3d12Device(d3d12Device), : d3d12Device(d3d12Device),
commandAllocatorManager(new CommandAllocatorManager(this)), commandAllocatorManager(new CommandAllocatorManager(this)),
descriptorHeapAllocator(new DescriptorHeapAllocator(this)),
resourceAllocator(new ResourceAllocator(this)), resourceAllocator(new ResourceAllocator(this)),
resourceUploader(new ResourceUploader(this)) { resourceUploader(new ResourceUploader(this)) {
@ -104,6 +108,10 @@ namespace d3d12 {
return commandQueue; return commandQueue;
} }
DescriptorHeapAllocator* Device::GetDescriptorHeapAllocator() {
return descriptorHeapAllocator;
}
ResourceAllocator* Device::GetResourceAllocator() { ResourceAllocator* Device::GetResourceAllocator() {
return resourceAllocator; return resourceAllocator;
} }
@ -142,6 +150,8 @@ namespace d3d12 {
void Device::SetNextRenderTargetDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor) { void Device::SetNextRenderTargetDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor) {
this->renderTargetDescriptor = 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() { void Device::TickImpl() {
@ -149,6 +159,7 @@ namespace d3d12 {
const uint64_t lastCompletedSerial = fence->GetCompletedValue(); const uint64_t lastCompletedSerial = fence->GetCompletedValue();
resourceAllocator->FreeUnusedResources(lastCompletedSerial); resourceAllocator->FreeUnusedResources(lastCompletedSerial);
commandAllocatorManager->ResetCompletedAllocators(lastCompletedSerial); commandAllocatorManager->ResetCompletedAllocators(lastCompletedSerial);
descriptorHeapAllocator->FreeDescriptorHeaps(lastCompletedSerial);
} }
uint64_t Device::GetSerial() const { uint64_t Device::GetSerial() const {
@ -219,7 +230,7 @@ namespace d3d12 {
return new RenderPass(this, builder); return new RenderPass(this, builder);
} }
SamplerBase* Device::CreateSampler(SamplerBuilder* builder) { SamplerBase* Device::CreateSampler(SamplerBuilder* builder) {
return new Sampler(this, builder); return new Sampler(builder);
} }
ShaderModuleBase* Device::CreateShaderModule(ShaderModuleBuilder* builder) { ShaderModuleBase* Device::CreateShaderModule(ShaderModuleBuilder* builder) {
return new ShaderModule(this, builder); return new ShaderModule(this, builder);
@ -249,12 +260,6 @@ namespace d3d12 {
: BindGroupLayoutBase(builder), device(device) { : BindGroupLayoutBase(builder), device(device) {
} }
// BufferView
BufferView::BufferView(Device* device, BufferViewBuilder* builder)
: BufferViewBase(builder), device(device) {
}
// DepthStencilState // DepthStencilState
DepthStencilState::DepthStencilState(Device* device, DepthStencilStateBuilder* builder) DepthStencilState::DepthStencilState(Device* device, DepthStencilStateBuilder* builder)
@ -273,26 +278,5 @@ namespace d3d12 {
: RenderPassBase(builder), device(device) { : 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) {
}
} }
} }

View File

@ -55,6 +55,7 @@ namespace d3d12 {
class RenderPass; class RenderPass;
class CommandAllocatorManager; class CommandAllocatorManager;
class DescriptorHeapAllocator;
class ResourceAllocator; class ResourceAllocator;
class ResourceUploader; class ResourceUploader;
@ -113,6 +114,7 @@ namespace d3d12 {
ComPtr<ID3D12Device> GetD3D12Device(); ComPtr<ID3D12Device> GetD3D12Device();
ComPtr<ID3D12CommandQueue> GetCommandQueue(); ComPtr<ID3D12CommandQueue> GetCommandQueue();
DescriptorHeapAllocator* GetDescriptorHeapAllocator();
ResourceAllocator* GetResourceAllocator(); ResourceAllocator* GetResourceAllocator();
ResourceUploader* GetResourceUploader(); ResourceUploader* GetResourceUploader();
@ -141,6 +143,7 @@ namespace d3d12 {
ComPtr<ID3D12CommandQueue> commandQueue; ComPtr<ID3D12CommandQueue> commandQueue;
CommandAllocatorManager* commandAllocatorManager; CommandAllocatorManager* commandAllocatorManager;
DescriptorHeapAllocator* descriptorHeapAllocator;
ResourceAllocator* resourceAllocator; ResourceAllocator* resourceAllocator;
ResourceUploader* resourceUploader; ResourceUploader* resourceUploader;
@ -169,14 +172,6 @@ namespace d3d12 {
Device* device; Device* device;
}; };
class BufferView : public BufferViewBase {
public:
BufferView(Device* device, BufferViewBuilder* builder);
private:
Device* device;
};
class Framebuffer : public FramebufferBase { class Framebuffer : public FramebufferBase {
public: public:
Framebuffer(Device* device, FramebufferBuilder* builder); Framebuffer(Device* device, FramebufferBuilder* builder);
@ -201,32 +196,6 @@ namespace d3d12 {
Device* device; 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;
};
} }
} }

View File

@ -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<ID3D12DescriptorHeap> 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<ID3D12DescriptorHeap> 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());
}
}
}

View File

@ -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 <array>
#include <vector>
namespace backend {
namespace d3d12 {
class Device;
class DescriptorHeapHandle {
public:
DescriptorHeapHandle();
DescriptorHeapHandle(ComPtr<ID3D12DescriptorHeap> 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<ID3D12DescriptorHeap> 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<ComPtr<ID3D12DescriptorHeap>, AllocationInfo>;
using DescriptorHeapPoolList = std::vector<DescriptorHeapPool>;
std::array<uint32_t, kDescriptorHeapTypes> sizeIncrements;
std::array<DescriptorHeapPoolList, kDescriptorHeapTypes> descriptorHeapPools;
SerialQueue<DescriptorHeapHandle> releasedHandles;
};
}
}
#endif // BACKEND_D3D12_DESCRIPTORHEAPALLOCATOR_H_

View File

@ -19,4 +19,6 @@
#include "PipelineD3D12.h" #include "PipelineD3D12.h"
#include "PipelineLayoutD3D12.h" #include "PipelineLayoutD3D12.h"
#include "QueueD3D12.h" #include "QueueD3D12.h"
#include "SamplerD3D12.h"
#include "ShaderModuleD3D12.h" #include "ShaderModuleD3D12.h"
#include "TextureD3D12.h"

View File

@ -32,6 +32,8 @@ namespace d3d12 {
// Enable better shader debugging with the graphics debugging tools. // Enable better shader debugging with the graphics debugging tools.
compileFlags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; compileFlags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#endif #endif
// SPRIV-cross does matrix multiplication expecting row major matrices
compileFlags |= D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
if (IsCompute()) { if (IsCompute()) {
const auto& module = ToBackend(builder->GetStageInfo(nxt::ShaderStage::Compute).module); const auto& module = ToBackend(builder->GetStageInfo(nxt::ShaderStage::Compute).module);
@ -54,7 +56,7 @@ namespace d3d12 {
&compiledShader, &compiledShader,
&errors &errors
))) { ))) {
printf("%s\n", errors->GetBufferPointer()); printf("%s\n", reinterpret_cast<char*>(errors->GetBufferPointer()));
ASSERT(false); ASSERT(false);
} }
@ -82,11 +84,11 @@ namespace d3d12 {
switch (stage) { switch (stage) {
case nxt::ShaderStage::Vertex: case nxt::ShaderStage::Vertex:
shader = &descriptor.VS; shader = &descriptor.VS;
compileTarget = "vs_5_0"; compileTarget = "vs_5_1";
break; break;
case nxt::ShaderStage::Fragment: case nxt::ShaderStage::Fragment:
shader = &descriptor.PS; shader = &descriptor.PS;
compileTarget = "ps_5_0"; compileTarget = "ps_5_1";
break; break;
case nxt::ShaderStage::Compute: case nxt::ShaderStage::Compute:
ASSERT(false); ASSERT(false);
@ -106,7 +108,7 @@ namespace d3d12 {
&compiledShader[stage], &compiledShader[stage],
&errors &errors
))) { ))) {
printf("%s\n", errors->GetBufferPointer()); printf("%s\n", reinterpret_cast<char*>(errors->GetBufferPointer()));
ASSERT(false); ASSERT(false);
} }
@ -116,10 +118,15 @@ namespace d3d12 {
} }
} }
InputState* inputState = ToBackend(GetInputState()); PipelineLayout* layout = ToBackend(GetLayout());
descriptor.InputLayout = inputState->GetD3D12InputLayoutDescriptor();
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.FillMode = D3D12_FILL_MODE_SOLID;
descriptor.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; descriptor.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;

View File

@ -15,6 +15,7 @@
#include "PipelineLayoutD3D12.h" #include "PipelineLayoutD3D12.h"
#include "D3D12Backend.h" #include "D3D12Backend.h"
#include "BindGroupLayoutD3D12.h"
using Microsoft::WRL::ComPtr; using Microsoft::WRL::ComPtr;
@ -24,10 +25,59 @@ namespace d3d12 {
PipelineLayout::PipelineLayout(Device* device, PipelineLayoutBuilder* builder) PipelineLayout::PipelineLayout(Device* device, PipelineLayoutBuilder* builder)
: PipelineLayoutBase(builder), device(device) { : 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; D3D12_ROOT_SIGNATURE_DESC rootSignatureDescriptor;
rootSignatureDescriptor.NumParameters = 0; rootSignatureDescriptor.NumParameters = parameterIndex;
rootSignatureDescriptor.pParameters = nullptr; rootSignatureDescriptor.pParameters = rootParameters;
rootSignatureDescriptor.NumStaticSamplers = 0; rootSignatureDescriptor.NumStaticSamplers = 0;
rootSignatureDescriptor.pStaticSamplers = nullptr; rootSignatureDescriptor.pStaticSamplers = nullptr;
rootSignatureDescriptor.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; 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))); 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<ID3D12RootSignature> PipelineLayout::GetRootSignature() { ComPtr<ID3D12RootSignature> PipelineLayout::GetRootSignature() {
return rootSignature; return rootSignature;
} }
} }
} }

View File

@ -28,11 +28,35 @@ namespace d3d12 {
public: public:
PipelineLayout(Device* device, PipelineLayoutBuilder* builder); PipelineLayout(Device* device, PipelineLayoutBuilder* builder);
class Descriptor {
public:
enum class Type {
CBV,
UAV,
SRV,
Sampler,
Count
};
static constexpr unsigned int TypeCount = static_cast<typename std::underlying_type<Type>::type>(Type::Count);
};
uint32_t GetCbvUavSrvRootParameterIndex(uint32_t group) const;
uint32_t GetSamplerRootParameterIndex(uint32_t group) const;
ComPtr<ID3D12RootSignature> GetRootSignature(); ComPtr<ID3D12RootSignature> GetRootSignature();
private: private:
static constexpr unsigned int ToIndex(Descriptor::Type type) {
return static_cast<typename std::underlying_type<Descriptor::Type>::type>(type);
}
Device* device; Device* device;
std::array<uint32_t, kMaxBindGroups> cbvUavSrvRootParameterInfo;
std::array<uint32_t, kMaxBindGroups> samplerRootParameterInfo;
std::array<std::array<uint32_t, Descriptor::TypeCount>, kMaxBindGroups> descriptorCountInfo;
ComPtr<ID3D12RootSignature> rootSignature; ComPtr<ID3D12RootSignature> rootSignature;
}; };

View File

@ -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<D3D12_FILTER>(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;
}
}
}

View File

@ -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_

View File

@ -24,7 +24,7 @@ namespace d3d12 {
spirv_cross::CompilerHLSL compiler(builder->AcquireSpirv()); spirv_cross::CompilerHLSL compiler(builder->AcquireSpirv());
spirv_cross::CompilerHLSL::Options options; spirv_cross::CompilerHLSL::Options options;
options.shader_model = 40; options.shader_model = 51;
options.flip_vert_y = false; options.flip_vert_y = false;
options.fixup_clipspace = true; options.fixup_clipspace = true;
@ -32,7 +32,46 @@ namespace d3d12 {
ExtractSpirvInfo(compiler); ExtractSpirvInfo(compiler);
enum RegisterType {
Buffer,
UnorderedAccess,
Texture,
Sampler,
Count,
};
std::array<uint32_t, RegisterType::Count * kMaxBindGroups> 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<spirv_cross::Resource> 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(); 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 { const std::string& ShaderModule::GetHLSLSource() const {

View File

@ -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<ID3D12Resource> 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;
}
}
}

View File

@ -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<ID3D12Resource> GetD3D12Resource();
bool GetResourceTransitionBarrier(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier);
private:
Device* device;
ComPtr<ID3D12Resource> 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_