D3D12 vertex and index buffers with resource transitions
This commit is contained in:
parent
459537491b
commit
d251356783
|
@ -216,10 +216,14 @@ if (WIN32)
|
|||
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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_
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 @@ namespace d3d12 {
|
|||
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 @@ namespace d3d12 {
|
|||
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 @@ namespace d3d12 {
|
|||
: 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 @@ namespace d3d12 {
|
|||
: FramebufferBase(builder), device(device) {
|
||||
}
|
||||
|
||||
// InputState
|
||||
|
||||
InputState::InputState(Device* device, InputStateBuilder * builder)
|
||||
: InputStateBase(builder), device(device) {
|
||||
}
|
||||
|
||||
// RenderPass
|
||||
|
||||
RenderPass::RenderPass(Device* device, RenderPassBuilder* builder)
|
||||
|
|
|
@ -106,6 +106,8 @@ namespace d3d12 {
|
|||
|
||||
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 @@ namespace d3d12 {
|
|||
private:
|
||||
ComPtr<ID3D12Device> d3d12Device;
|
||||
ComPtr<ID3D12CommandQueue> commandQueue;
|
||||
ComPtr<ID3D12CommandAllocator> pendingCommandAllocator;
|
||||
ComPtr<ID3D12GraphicsCommandList> pendingCommandList;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor;
|
||||
};
|
||||
|
||||
|
@ -137,19 +141,6 @@ namespace d3d12 {
|
|||
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 @@ namespace d3d12 {
|
|||
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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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_
|
|
@ -15,6 +15,7 @@
|
|||
#include "PipelineD3D12.h"
|
||||
|
||||
#include "D3D12Backend.h"
|
||||
#include "InputStateD3D12.h"
|
||||
#include "ShaderModuleD3D12.h"
|
||||
#include "PipelineLayoutD3D12.h"
|
||||
|
||||
|
@ -115,6 +116,9 @@ namespace d3d12 {
|
|||
}
|
||||
}
|
||||
|
||||
InputState* inputState = ToBackend(GetInputState());
|
||||
descriptor.InputLayout = inputState->GetD3D12InputLayoutDescriptor();
|
||||
|
||||
descriptor.pRootSignature = ToBackend(GetLayout())->GetRootSignature().Get();
|
||||
|
||||
descriptor.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
||||
|
|
|
@ -31,7 +31,6 @@ namespace d3d12 {
|
|||
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 @@ namespace d3d12 {
|
|||
}
|
||||
|
||||
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 @@ namespace d3d12 {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue