D3D12 vertex and index buffers with resource transitions
diff --git a/src/backend/CMakeLists.txt b/src/backend/CMakeLists.txt
index a9b2552..6177535 100644
--- a/src/backend/CMakeLists.txt
+++ b/src/backend/CMakeLists.txt
@@ -216,10 +216,14 @@
SetPIC(d3d12_autogen)
list(APPEND BACKEND_SOURCES
+ ${D3D12_DIR}/BufferD3D12.cpp
+ ${D3D12_DIR}/BufferD3D12.h
${D3D12_DIR}/CommandBufferD3D12.cpp
${D3D12_DIR}/CommandBufferD3D12.h
${D3D12_DIR}/D3D12Backend.cpp
${D3D12_DIR}/D3D12Backend.h
+ ${D3D12_DIR}/InputStateD3D12.cpp
+ ${D3D12_DIR}/InputStateD3D12.h
${D3D12_DIR}/PipelineD3D12.cpp
${D3D12_DIR}/PipelineD3D12.h
${D3D12_DIR}/PipelineLayoutD3D12.cpp
diff --git a/src/backend/d3d12/BufferD3D12.cpp b/src/backend/d3d12/BufferD3D12.cpp
new file mode 100644
index 0000000..d837cba
--- /dev/null
+++ b/src/backend/d3d12/BufferD3D12.cpp
@@ -0,0 +1,163 @@
+// 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 "BufferD3D12.h"
+
+#include "D3D12Backend.h"
+
+namespace backend {
+namespace d3d12 {
+
+ namespace {
+ D3D12_RESOURCE_STATES D3D12BufferUsage(nxt::BufferUsageBit usage) {
+ D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_COMMON;
+
+ if (usage & nxt::BufferUsageBit::TransferSrc) {
+ resourceState |= D3D12_RESOURCE_STATE_COPY_SOURCE;
+ }
+ if (usage & nxt::BufferUsageBit::TransferDst) {
+ resourceState |= D3D12_RESOURCE_STATE_COPY_DEST;
+ }
+ if (usage & (nxt::BufferUsageBit::Vertex | nxt::BufferUsageBit::Uniform)) {
+ resourceState |= D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
+ }
+ if (usage & nxt::BufferUsageBit::Index) {
+ resourceState |= D3D12_RESOURCE_STATE_INDEX_BUFFER;
+ }
+ if (usage & nxt::BufferUsageBit::Storage) {
+ resourceState |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
+ }
+
+ return resourceState;
+ }
+ }
+
+ Buffer::Buffer(Device* device, BufferBuilder* builder)
+ : BufferBase(builder), device(device) {
+
+ D3D12_RESOURCE_DESC resourceDescriptor;
+ resourceDescriptor.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ resourceDescriptor.Alignment = 0;
+ resourceDescriptor.Width = GetSize();
+ resourceDescriptor.Height = 1;
+ resourceDescriptor.DepthOrArraySize = 1;
+ resourceDescriptor.MipLevels = 1;
+ resourceDescriptor.Format = DXGI_FORMAT_UNKNOWN;
+ resourceDescriptor.SampleDesc.Count = 1;
+ resourceDescriptor.SampleDesc.Quality = 0;
+ resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+ resourceDescriptor.Flags = D3D12_RESOURCE_FLAG_NONE;
+
+ {
+ D3D12_HEAP_PROPERTIES heapProperties;
+ heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
+ heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+ heapProperties.CreationNodeMask = 0;
+ heapProperties.VisibleNodeMask = 0;
+
+ ASSERT_SUCCESS(device->GetD3D12Device()->CreateCommittedResource(
+ &heapProperties,
+ D3D12_HEAP_FLAG_NONE,
+ &resourceDescriptor,
+ D3D12_RESOURCE_STATE_GENERIC_READ,
+ nullptr,
+ IID_PPV_ARGS(&uploadResource)
+ ));
+ }
+
+ {
+ D3D12_HEAP_PROPERTIES heapProperties;
+ heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
+ heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+ heapProperties.CreationNodeMask = 0;
+ heapProperties.VisibleNodeMask = 0;
+
+ ASSERT_SUCCESS(device->GetD3D12Device()->CreateCommittedResource(
+ &heapProperties,
+ D3D12_HEAP_FLAG_NONE,
+ &resourceDescriptor,
+ D3D12BufferUsage(GetUsage()),
+ nullptr,
+ IID_PPV_ARGS(&resource)
+ ));
+ }
+ }
+
+ ComPtr<ID3D12Resource> Buffer::GetD3D12Resource() {
+ return resource;
+ }
+
+ bool Buffer::GetResourceTransitionBarrier(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier) {
+ D3D12_RESOURCE_STATES stateBefore = D3D12BufferUsage(currentUsage);
+ D3D12_RESOURCE_STATES stateAfter = D3D12BufferUsage(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;
+ }
+
+ D3D12_GPU_VIRTUAL_ADDRESS Buffer::GetVA() const {
+ return resource->GetGPUVirtualAddress();
+ }
+
+ void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) {
+ uint32_t begin = start * sizeof(uint32_t);
+ uint32_t end = (start + count) * sizeof(uint32_t);
+
+ uint8_t* mappedResource = nullptr;
+
+ D3D12_RANGE readRange;
+ readRange.Begin = 0;
+ readRange.End = 0;
+
+ ASSERT_SUCCESS(uploadResource->Map(0, &readRange, reinterpret_cast<void**>(&mappedResource)));
+ memcpy(&mappedResource[begin], data, end - begin);
+
+ D3D12_RANGE writeRange;
+ writeRange.Begin = begin;
+ writeRange.End = end;
+
+ uploadResource->Unmap(0, &writeRange);
+
+ device->GetPendingCommandList()->CopyBufferRegion(resource.Get(), begin, uploadResource.Get(), begin, end - begin);
+ }
+
+ void Buffer::MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) {
+ // TODO(cwallez@chromium.org): Implement Map Read for the null backend
+ }
+
+ void Buffer::UnmapImpl() {
+ // TODO(cwallez@chromium.org): Implement Map Read for the null backend
+ }
+
+ void Buffer::TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) {
+ D3D12_RESOURCE_BARRIER barrier;
+ if (GetResourceTransitionBarrier(currentUsage, targetUsage, &barrier)) {
+ device->GetPendingCommandList()->ResourceBarrier(1, &barrier);
+ }
+ }
+
+}
+}
diff --git a/src/backend/d3d12/BufferD3D12.h b/src/backend/d3d12/BufferD3D12.h
new file mode 100644
index 0000000..6ff12e7
--- /dev/null
+++ b/src/backend/d3d12/BufferD3D12.h
@@ -0,0 +1,51 @@
+// 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_BUFFERD3D12_H_
+#define BACKEND_D3D12_BUFFERD3D12_H_
+
+#include "common/Buffer.h"
+
+#include "d3d12_platform.h"
+
+namespace backend {
+namespace d3d12 {
+
+ class Device;
+
+ class Buffer : public BufferBase {
+ public:
+ Buffer(Device* device, BufferBuilder* builder);
+
+ ComPtr<ID3D12Resource> GetD3D12Resource();
+ D3D12_GPU_VIRTUAL_ADDRESS GetVA() const;
+ bool GetResourceTransitionBarrier(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier);
+
+ private:
+ Device* device;
+ ComPtr<ID3D12Resource> uploadResource;
+ ComPtr<ID3D12Resource> resource;
+
+ // NXT API
+ void SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) override;
+ void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override;
+ void UnmapImpl() override;
+ void TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) override;
+
+ };
+
+}
+}
+
+#endif // BACKEND_D3D12_BUFFERD3D12_H_
diff --git a/src/backend/d3d12/CommandBufferD3D12.cpp b/src/backend/d3d12/CommandBufferD3D12.cpp
index 95306a6..1d5ebd8 100644
--- a/src/backend/d3d12/CommandBufferD3D12.cpp
+++ b/src/backend/d3d12/CommandBufferD3D12.cpp
@@ -16,156 +16,212 @@
#include "common/Commands.h"
#include "D3D12Backend.h"
+#include "BufferD3D12.h"
+#include "InputStateD3D12.h"
#include "PipelineD3D12.h"
#include "PipelineLayoutD3D12.h"
namespace backend {
namespace d3d12 {
- CommandBuffer::CommandBuffer(Device* device, CommandBufferBuilder* builder)
- : CommandBufferBase(builder), device(device), commands(builder->AcquireCommands()) {
- }
+ namespace {
+ DXGI_FORMAT DXGIIndexFormat(nxt::IndexFormat format) {
+ switch (format) {
+ case nxt::IndexFormat::Uint16:
+ return DXGI_FORMAT_R16_UINT;
+ case nxt::IndexFormat::Uint32:
+ return DXGI_FORMAT_R32_UINT;
+ }
+ }
+ }
- CommandBuffer::~CommandBuffer() {
- FreeCommands(&commands);
- }
+ CommandBuffer::CommandBuffer(Device* device, CommandBufferBuilder* builder)
+ : CommandBufferBase(builder), device(device), commands(builder->AcquireCommands()) {
+ }
- void CommandBuffer::FillCommands(ComPtr<ID3D12GraphicsCommandList> commandList) {
- Command type;
- Pipeline* lastPipeline = nullptr;
+ CommandBuffer::~CommandBuffer() {
+ FreeCommands(&commands);
+ }
- RenderPass* currentRenderPass = nullptr;
- Framebuffer* currentFramebuffer = nullptr;
+ void CommandBuffer::FillCommands(ComPtr<ID3D12GraphicsCommandList> commandList) {
+ Command type;
+ Pipeline* lastPipeline = nullptr;
- while(commands.NextCommandId(&type)) {
- switch (type) {
- case Command::AdvanceSubpass:
- {
- commands.NextCommand<AdvanceSubpassCmd>();
- }
- break;
+ RenderPass* currentRenderPass = nullptr;
+ Framebuffer* currentFramebuffer = nullptr;
- case Command::BeginRenderPass:
- {
- BeginRenderPassCmd* beginRenderPassCmd = commands.NextCommand<BeginRenderPassCmd>();
- currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get());
- currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get());
+ while(commands.NextCommandId(&type)) {
+ switch (type) {
+ case Command::AdvanceSubpass:
+ {
+ commands.NextCommand<AdvanceSubpassCmd>();
+ }
+ break;
- 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 };
- commandList->RSSetViewports(1, &viewport);
- commandList->RSSetScissorRects(1, &scissorRect);
- commandList->OMSetRenderTargets(1, &device->GetCurrentRenderTargetDescriptor(), FALSE, nullptr);
- }
- break;
+ case Command::BeginRenderPass:
+ {
+ BeginRenderPassCmd* beginRenderPassCmd = commands.NextCommand<BeginRenderPassCmd>();
+ currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get());
+ currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get());
- case Command::CopyBufferToBuffer:
- {
- CopyBufferToBufferCmd* copy = commands.NextCommand<CopyBufferToBufferCmd>();
- }
- break;
+ 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 };
+ commandList->RSSetViewports(1, &viewport);
+ commandList->RSSetScissorRects(1, &scissorRect);
+ commandList->OMSetRenderTargets(1, &device->GetCurrentRenderTargetDescriptor(), FALSE, nullptr);
+ }
+ break;
+ case Command::CopyBufferToBuffer:
+ {
+ CopyBufferToBufferCmd* copy = commands.NextCommand<CopyBufferToBufferCmd>();
+ }
+ break;
- case Command::CopyBufferToTexture:
- {
- CopyBufferToTextureCmd* copy = commands.NextCommand<CopyBufferToTextureCmd>();
- }
- break;
+ case Command::CopyBufferToTexture:
+ {
+ CopyBufferToTextureCmd* copy = commands.NextCommand<CopyBufferToTextureCmd>();
+ }
+ break;
- case Command::Dispatch:
- {
- DispatchCmd* dispatch = commands.NextCommand<DispatchCmd>();
+ case Command::Dispatch:
+ {
+ DispatchCmd* dispatch = commands.NextCommand<DispatchCmd>();
- ASSERT(lastPipeline->IsCompute());
- commandList->Dispatch(dispatch->x, dispatch->y, dispatch->z);
- }
- break;
+ ASSERT(lastPipeline->IsCompute());
+ commandList->Dispatch(dispatch->x, dispatch->y, dispatch->z);
+ }
+ break;
- case Command::DrawArrays:
- {
- DrawArraysCmd* draw = commands.NextCommand<DrawArraysCmd>();
+ case Command::DrawArrays:
+ {
+ DrawArraysCmd* draw = commands.NextCommand<DrawArraysCmd>();
- commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
- commandList->DrawInstanced(
- draw->vertexCount,
- draw->instanceCount,
- draw->firstVertex,
- draw->firstInstance
- );
- }
- break;
+ commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ commandList->DrawInstanced(
+ draw->vertexCount,
+ draw->instanceCount,
+ draw->firstVertex,
+ draw->firstInstance
+ );
+ }
+ break;
- case Command::DrawElements:
- {
- DrawElementsCmd* draw = commands.NextCommand<DrawElementsCmd>();
- }
- break;
+ case Command::DrawElements:
+ {
+ DrawElementsCmd* draw = commands.NextCommand<DrawElementsCmd>();
- case Command::EndRenderPass:
- {
- EndRenderPassCmd* cmd = commands.NextCommand<EndRenderPassCmd>();
- }
- break;
+ commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ commandList->DrawIndexedInstanced(
+ draw->indexCount,
+ draw->instanceCount,
+ draw->firstIndex,
+ 0,
+ draw->firstInstance
+ );
+ }
+ break;
- case Command::SetPipeline:
- {
- SetPipelineCmd* cmd = commands.NextCommand<SetPipelineCmd>();
- lastPipeline = ToBackend(cmd->pipeline).Get();
- PipelineLayout* pipelineLayout = ToBackend(lastPipeline->GetLayout());
+ case Command::EndRenderPass:
+ {
+ EndRenderPassCmd* cmd = commands.NextCommand<EndRenderPassCmd>();
+ }
+ break;
- // TODO
- if (lastPipeline->IsCompute()) {
- } else {
- commandList->SetGraphicsRootSignature(pipelineLayout->GetRootSignature().Get());
- commandList->SetPipelineState(lastPipeline->GetRenderPipelineState().Get());
- }
- }
- break;
+ case Command::SetPipeline:
+ {
+ SetPipelineCmd* cmd = commands.NextCommand<SetPipelineCmd>();
+ lastPipeline = ToBackend(cmd->pipeline).Get();
+ PipelineLayout* pipelineLayout = ToBackend(lastPipeline->GetLayout());
- case Command::SetPushConstants:
- {
- SetPushConstantsCmd* cmd = commands.NextCommand<SetPushConstantsCmd>();
- }
- break;
+ // TODO
+ if (lastPipeline->IsCompute()) {
+ } else {
+ commandList->SetGraphicsRootSignature(pipelineLayout->GetRootSignature().Get());
+ commandList->SetPipelineState(lastPipeline->GetRenderPipelineState().Get());
+ }
+ }
+ break;
- case Command::SetStencilReference:
+ case Command::SetPushConstants:
+ {
+ SetPushConstantsCmd* cmd = commands.NextCommand<SetPushConstantsCmd>();
+ }
+ break;
+
+ case Command::SetStencilReference:
{
SetStencilReferenceCmd* cmd = commands.NextCommand<SetStencilReferenceCmd>();
}
break;
- case Command::SetBindGroup:
- {
- SetBindGroupCmd* cmd = commands.NextCommand<SetBindGroupCmd>();
- }
- break;
+ case Command::SetBindGroup:
+ {
+ SetBindGroupCmd* cmd = commands.NextCommand<SetBindGroupCmd>();
+ }
+ break;
- case Command::SetIndexBuffer:
- {
- SetIndexBufferCmd* cmd = commands.NextCommand<SetIndexBufferCmd>();
- }
- break;
+ case Command::SetIndexBuffer:
+ {
+ SetIndexBufferCmd* cmd = commands.NextCommand<SetIndexBufferCmd>();
- case Command::SetVertexBuffers:
- {
- SetVertexBuffersCmd* cmd = commands.NextCommand<SetVertexBuffersCmd>();
- }
- break;
+ Buffer* buffer = ToBackend(cmd->buffer.Get());
+ D3D12_INDEX_BUFFER_VIEW bufferView;
+ bufferView.BufferLocation = buffer->GetVA() + cmd->offset;
+ bufferView.SizeInBytes = buffer->GetSize() - cmd->offset;
+ bufferView.Format = DXGIIndexFormat(cmd->format);
- case Command::TransitionBufferUsage:
- {
- TransitionBufferUsageCmd* cmd = commands.NextCommand<TransitionBufferUsageCmd>();
- }
- break;
+ commandList->IASetIndexBuffer(&bufferView);
+ }
+ break;
- case Command::TransitionTextureUsage:
- {
- TransitionTextureUsageCmd* cmd = commands.NextCommand<TransitionTextureUsageCmd>();
- }
- break;
- }
- }
- }
+ case Command::SetVertexBuffers:
+ {
+ SetVertexBuffersCmd* cmd = commands.NextCommand<SetVertexBuffersCmd>();
+ auto buffers = commands.NextData<Ref<BufferBase>>(cmd->count);
+ auto offsets = commands.NextData<uint32_t>(cmd->count);
+
+ auto inputState = ToBackend(lastPipeline->GetInputState());
+
+ std::array<D3D12_VERTEX_BUFFER_VIEW, kMaxVertexInputs> d3d12BufferViews;
+ for (uint32_t i = 0; i < cmd->count; ++i) {
+ auto input = inputState->GetInput(cmd->startSlot + i);
+ Buffer* buffer = ToBackend(buffers[i].Get());
+ d3d12BufferViews[i].BufferLocation = buffer->GetVA() + offsets[i];
+ d3d12BufferViews[i].StrideInBytes = input.stride;
+ d3d12BufferViews[i].SizeInBytes = buffer->GetSize() - offsets[i];
+ }
+
+ commandList->IASetVertexBuffers(cmd->startSlot, cmd->count, d3d12BufferViews.data());
+ }
+ break;
+
+ case Command::TransitionBufferUsage:
+ {
+ TransitionBufferUsageCmd* cmd = commands.NextCommand<TransitionBufferUsageCmd>();
+
+ Buffer* buffer = ToBackend(cmd->buffer.Get());
+
+ D3D12_RESOURCE_BARRIER barrier;
+ if (buffer->GetResourceTransitionBarrier(buffer->GetUsage(), cmd->usage, &barrier)) {
+ commandList->ResourceBarrier(1, &barrier);
+ }
+
+ buffer->UpdateUsageInternal(cmd->usage);
+ }
+ break;
+
+ case Command::TransitionTextureUsage:
+ {
+ TransitionTextureUsageCmd* cmd = commands.NextCommand<TransitionTextureUsageCmd>();
+
+ Texture* texture = ToBackend(cmd->texture.Get());
+ texture->UpdateUsageInternal(cmd->usage);
+ }
+ break;
+ }
+ }
+ }
}
}
diff --git a/src/backend/d3d12/D3D12Backend.cpp b/src/backend/d3d12/D3D12Backend.cpp
index 6900bb9..5e9a142 100644
--- a/src/backend/d3d12/D3D12Backend.cpp
+++ b/src/backend/d3d12/D3D12Backend.cpp
@@ -14,7 +14,9 @@
#include "D3D12Backend.h"
+#include "BufferD3D12.h"
#include "CommandBufferD3D12.h"
+#include "InputStateD3D12.h"
#include "PipelineD3D12.h"
#include "PipelineLayoutD3D12.h"
#include "QueueD3D12.h"
@@ -51,6 +53,15 @@
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
ASSERT_SUCCESS(d3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue)));
+
+ ASSERT_SUCCESS(d3d12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&pendingCommandAllocator)));
+ ASSERT_SUCCESS(d3d12Device->CreateCommandList(
+ 0,
+ D3D12_COMMAND_LIST_TYPE_DIRECT,
+ pendingCommandAllocator.Get(),
+ nullptr,
+ IID_PPV_ARGS(&pendingCommandList)
+ ));
}
Device::~Device() {
@@ -64,6 +75,14 @@
return commandQueue;
}
+ ComPtr<ID3D12CommandAllocator> Device::GetPendingCommandAllocator() {
+ return pendingCommandAllocator;
+ }
+
+ ComPtr<ID3D12GraphicsCommandList> Device::GetPendingCommandList() {
+ return pendingCommandList;
+ }
+
D3D12_CPU_DESCRIPTOR_HANDLE Device::GetCurrentRenderTargetDescriptor() {
return renderTargetDescriptor;
}
@@ -139,26 +158,6 @@
: BindGroupLayoutBase(builder), device(device) {
}
- // Buffer
-
- Buffer::Buffer(Device* device, BufferBuilder* builder)
- : BufferBase(builder), device(device) {
- }
-
- void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) {
- }
-
- void Buffer::MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) {
- // TODO(cwallez@chromium.org): Implement Map Read for the null backend
- }
-
- void Buffer::UnmapImpl() {
- // TODO(cwallez@chromium.org): Implement Map Read for the null backend
- }
-
- void Buffer::TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) {
- }
-
// BufferView
BufferView::BufferView(Device* device, BufferViewBuilder* builder)
@@ -177,12 +176,6 @@
: FramebufferBase(builder), device(device) {
}
- // InputState
-
- InputState::InputState(Device* device, InputStateBuilder * builder)
- : InputStateBase(builder), device(device) {
- }
-
// RenderPass
RenderPass::RenderPass(Device* device, RenderPassBuilder* builder)
diff --git a/src/backend/d3d12/D3D12Backend.h b/src/backend/d3d12/D3D12Backend.h
index 8e1e193..cc0cd02 100644
--- a/src/backend/d3d12/D3D12Backend.h
+++ b/src/backend/d3d12/D3D12Backend.h
@@ -106,6 +106,8 @@
ComPtr<ID3D12Device> GetD3D12Device();
ComPtr<ID3D12CommandQueue> GetCommandQueue();
+ ComPtr<ID3D12CommandAllocator> GetPendingCommandAllocator();
+ ComPtr<ID3D12GraphicsCommandList> GetPendingCommandList();
D3D12_CPU_DESCRIPTOR_HANDLE GetCurrentRenderTargetDescriptor();
void SetNextRenderTargetDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor);
@@ -117,6 +119,8 @@
private:
ComPtr<ID3D12Device> d3d12Device;
ComPtr<ID3D12CommandQueue> commandQueue;
+ ComPtr<ID3D12CommandAllocator> pendingCommandAllocator;
+ ComPtr<ID3D12GraphicsCommandList> pendingCommandList;
D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor;
};
@@ -137,19 +141,6 @@
Device* device;
};
- class Buffer : public BufferBase {
- public:
- Buffer(Device* device, BufferBuilder* builder);
-
- private:
- void SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) override;
- void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override;
- void UnmapImpl() override;
- void TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) override;
-
- Device* device;
- };
-
class BufferView : public BufferViewBase {
public:
BufferView(Device* device, BufferViewBuilder* builder);
@@ -174,14 +165,6 @@
Device* device;
};
- class InputState : public InputStateBase {
- public:
- InputState(Device* device, InputStateBuilder* builder);
-
- private:
- Device* device;
- };
-
class RenderPass : public RenderPassBase {
public:
RenderPass(Device* device, RenderPassBuilder* builder);
diff --git a/src/backend/d3d12/GeneratedCodeIncludes.h b/src/backend/d3d12/GeneratedCodeIncludes.h
index f2e322f..0f776b9 100644
--- a/src/backend/d3d12/GeneratedCodeIncludes.h
+++ b/src/backend/d3d12/GeneratedCodeIncludes.h
@@ -13,7 +13,9 @@
// limitations under the License.
#include "D3D12Backend.h"
+#include "BufferD3D12.h"
#include "CommandBufferD3D12.h"
+#include "InputStateD3D12.h"
#include "PipelineD3D12.h"
#include "PipelineLayoutD3D12.h"
#include "QueueD3D12.h"
diff --git a/src/backend/d3d12/InputStateD3D12.cpp b/src/backend/d3d12/InputStateD3D12.cpp
new file mode 100644
index 0000000..e0abcb0
--- /dev/null
+++ b/src/backend/d3d12/InputStateD3D12.cpp
@@ -0,0 +1,82 @@
+// 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 "InputStateD3D12.h"
+
+namespace backend {
+namespace d3d12 {
+
+ static DXGI_FORMAT VertexFormatType(nxt::VertexFormat format) {
+ switch (format) {
+ case nxt::VertexFormat::FloatR32G32B32A32:
+ return DXGI_FORMAT_R32G32B32A32_FLOAT;
+ case nxt::VertexFormat::FloatR32G32B32:
+ return DXGI_FORMAT_R32G32B32_FLOAT;
+ case nxt::VertexFormat::FloatR32G32:
+ return DXGI_FORMAT_R32G32_FLOAT;
+ }
+ }
+
+ static D3D12_INPUT_CLASSIFICATION InputStepModeFunction(nxt::InputStepMode mode) {
+ switch (mode) {
+ case nxt::InputStepMode::Vertex:
+ return D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
+ case nxt::InputStepMode::Instance:
+ return D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
+ }
+ }
+
+ InputState::InputState(Device* device, InputStateBuilder* builder)
+ : InputStateBase(builder), device(device) {
+
+ const auto& attributesSetMask = GetAttributesSetMask();
+
+ size_t count = 0;
+ for (size_t i = 0; i < attributesSetMask.size(); ++i) {
+ if (!attributesSetMask[i]) {
+ continue;
+ }
+
+ D3D12_INPUT_ELEMENT_DESC& inputElementDescriptor = inputElementDescriptors[count++];
+
+ const AttributeInfo& attribute = GetAttribute(i);
+
+ // If the HLSL semantic is TEXCOORDN the SemanticName should be "TEXCOORD" and the SemanticIndex N
+ inputElementDescriptor.SemanticName = "TEXCOORD";
+ inputElementDescriptor.SemanticIndex = i;
+ inputElementDescriptor.Format = VertexFormatType(attribute.format);
+ inputElementDescriptor.InputSlot = attribute.bindingSlot;
+
+ const InputInfo& input = GetInput(attribute.bindingSlot);
+
+ inputElementDescriptor.AlignedByteOffset = attribute.offset;
+ inputElementDescriptor.InputSlotClass = InputStepModeFunction(input.stepMode);
+ if (inputElementDescriptor.InputSlotClass == D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA) {
+ inputElementDescriptor.InstanceDataStepRate = 0;
+ } else {
+ inputElementDescriptor.InstanceDataStepRate = 1;
+ }
+ }
+
+ inputLayoutDescriptor.pInputElementDescs = inputElementDescriptors;
+ inputLayoutDescriptor.NumElements = count;
+
+ }
+
+ const D3D12_INPUT_LAYOUT_DESC& InputState::GetD3D12InputLayoutDescriptor() const {
+ return inputLayoutDescriptor;
+ }
+
+}
+}
diff --git a/src/backend/d3d12/InputStateD3D12.h b/src/backend/d3d12/InputStateD3D12.h
new file mode 100644
index 0000000..5dc2187
--- /dev/null
+++ b/src/backend/d3d12/InputStateD3D12.h
@@ -0,0 +1,42 @@
+// 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_INPUTSTATED3D12_H_
+#define BACKEND_D3D12_INPUTSTATED3D12_H_
+
+#include "common/InputState.h"
+
+#include "d3d12_platform.h"
+
+namespace backend {
+namespace d3d12 {
+
+ class Device;
+
+ class InputState : public InputStateBase {
+ public:
+ InputState(Device* device, InputStateBuilder* builder);
+
+ const D3D12_INPUT_LAYOUT_DESC& GetD3D12InputLayoutDescriptor() const;
+
+ private:
+ Device* device;
+ D3D12_INPUT_LAYOUT_DESC inputLayoutDescriptor;
+ D3D12_INPUT_ELEMENT_DESC inputElementDescriptors[kMaxVertexAttributes];
+ };
+
+}
+}
+
+#endif // BACKEND_D3D12_INPUTSTATED3D12_H_
diff --git a/src/backend/d3d12/PipelineD3D12.cpp b/src/backend/d3d12/PipelineD3D12.cpp
index be9562a..afcd3ae 100644
--- a/src/backend/d3d12/PipelineD3D12.cpp
+++ b/src/backend/d3d12/PipelineD3D12.cpp
@@ -15,6 +15,7 @@
#include "PipelineD3D12.h"
#include "D3D12Backend.h"
+#include "InputStateD3D12.h"
#include "ShaderModuleD3D12.h"
#include "PipelineLayoutD3D12.h"
@@ -115,6 +116,9 @@
}
}
+ InputState* inputState = ToBackend(GetInputState());
+ descriptor.InputLayout = inputState->GetD3D12InputLayoutDescriptor();
+
descriptor.pRootSignature = ToBackend(GetLayout())->GetRootSignature().Get();
descriptor.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
diff --git a/src/backend/d3d12/QueueD3D12.cpp b/src/backend/d3d12/QueueD3D12.cpp
index 7e8582f..4a5ef0f 100644
--- a/src/backend/d3d12/QueueD3D12.cpp
+++ b/src/backend/d3d12/QueueD3D12.cpp
@@ -31,7 +31,6 @@
nullptr,
IID_PPV_ARGS(&commandList)
));
- ASSERT_SUCCESS(commandList->Close());
ASSERT_SUCCESS(device->GetD3D12Device()->CreateFence(fenceValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)));
fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
@@ -39,10 +38,22 @@
}
void Queue::Submit(uint32_t numCommands, CommandBuffer* const * commands) {
- // TODO(enga@google.com): This will stall on the previous submit because
+ ComPtr<ID3D12CommandAllocator> pendingCommandAllocator = device->GetPendingCommandAllocator();
+ ComPtr<ID3D12GraphicsCommandList> pendingCommandList = device->GetPendingCommandList();
+ ASSERT_SUCCESS(pendingCommandList->Close());
+
+ for (uint32_t i = 0; i < numCommands; ++i) {
+ commands[i]->FillCommands(commandList);
+ }
+ ASSERT_SUCCESS(commandList->Close());
+
+ ID3D12CommandList* commandLists[] = { pendingCommandList.Get(), commandList.Get() };
+ device->GetCommandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+ // TODO(enga@google.com): This will stall on the submit because
// the commands must finish exeuting before the ID3D12CommandAllocator is reset.
// This should be fixed / optimized by using multiple command allocators.
- const uint64_t currentFence = fenceValue++;
+ const uint64_t currentFence = ++fenceValue;
ASSERT_SUCCESS(device->GetCommandQueue()->Signal(fence.Get(), fenceValue));
if (fence->GetCompletedValue() < currentFence) {
@@ -51,16 +62,9 @@
}
ASSERT_SUCCESS(commandAllocator->Reset());
+ ASSERT_SUCCESS(pendingCommandAllocator->Reset());
+ ASSERT_SUCCESS(pendingCommandList->Reset(pendingCommandAllocator.Get(), NULL));
ASSERT_SUCCESS(commandList->Reset(commandAllocator.Get(), NULL));
-
- for (uint32_t i = 0; i < numCommands; ++i) {
- commands[i]->FillCommands(commandList);
- }
-
- ASSERT_SUCCESS(commandList->Close());
-
- ID3D12CommandList* commandLists[] = { commandList.Get() };
- device->GetCommandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
}
}