mirror of https://github.com/axmolengine/axmol.git
852 lines
26 KiB
C++
852 lines
26 KiB
C++
|
#include "LLGI.CommandListDX12.h"
|
||
|
#include "LLGI.BufferDX12.h"
|
||
|
#include "LLGI.DescriptorHeapDX12.h"
|
||
|
#include "LLGI.GraphicsDX12.h"
|
||
|
#include "LLGI.PipelineStateDX12.h"
|
||
|
#include "LLGI.RenderPassDX12.h"
|
||
|
#include "LLGI.TextureDX12.h"
|
||
|
|
||
|
namespace LLGI
|
||
|
{
|
||
|
|
||
|
void CommandListDX12::BeginInternal()
|
||
|
{
|
||
|
rtDescriptorHeap_->Reset();
|
||
|
|
||
|
dtDescriptorHeap_->Reset();
|
||
|
|
||
|
cbDescriptorHeap_->Reset();
|
||
|
|
||
|
samplerDescriptorHeap_->Reset();
|
||
|
|
||
|
computeDescriptorHeap_->Reset();
|
||
|
}
|
||
|
|
||
|
CommandListDX12::CommandListDX12()
|
||
|
: samplerDescriptorHeap_(nullptr)
|
||
|
, cbDescriptorHeap_(nullptr)
|
||
|
, computeDescriptorHeap_(nullptr)
|
||
|
, rtDescriptorHeap_(nullptr)
|
||
|
, dtDescriptorHeap_(nullptr)
|
||
|
, commandList_(nullptr)
|
||
|
, commandAllocator_(nullptr)
|
||
|
, graphics_(nullptr)
|
||
|
, renderPass_(nullptr)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CommandListDX12::~CommandListDX12()
|
||
|
{
|
||
|
SafeRelease(fence_);
|
||
|
|
||
|
if (fenceEvent_ != nullptr)
|
||
|
{
|
||
|
CloseHandle(fenceEvent_);
|
||
|
fenceEvent_ = nullptr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool CommandListDX12::Initialize(GraphicsDX12* graphics, int32_t drawingCount)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
SafeAddRef(graphics);
|
||
|
graphics_ = CreateSharedPtr(graphics);
|
||
|
|
||
|
// Command Allocator
|
||
|
ID3D12CommandAllocator* commandAllocator = nullptr;
|
||
|
hr = graphics_->GetDevice()->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator));
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
auto msg = (std::string("Error : ") + std::string(__FILE__) + " : " + std::to_string(__LINE__) + std::string(" : ") +
|
||
|
std::system_category().message(hr));
|
||
|
::LLGI::Log(::LLGI::LogType::Error, msg.c_str());
|
||
|
SafeRelease(graphics_);
|
||
|
goto FAILED_EXIT;
|
||
|
}
|
||
|
commandAllocator_ = CreateSharedPtr(commandAllocator);
|
||
|
|
||
|
// Command List
|
||
|
ID3D12GraphicsCommandList* commandList = nullptr;
|
||
|
hr = graphics_->GetDevice()->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator, NULL, IID_PPV_ARGS(&commandList));
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
auto msg = (std::string("Error : ") + std::string(__FILE__) + " : " + std::to_string(__LINE__) + std::string(" : ") +
|
||
|
std::system_category().message(hr));
|
||
|
::LLGI::Log(::LLGI::LogType::Error, msg.c_str());
|
||
|
SafeRelease(graphics_);
|
||
|
SafeRelease(commandAllocator_);
|
||
|
goto FAILED_EXIT;
|
||
|
}
|
||
|
commandList->Close();
|
||
|
commandList_ = CreateSharedPtr(commandList);
|
||
|
|
||
|
rtDescriptorHeap_ =
|
||
|
std::make_shared<DX12::DescriptorHeapAllocator>(graphics_, D3D12_DESCRIPTOR_HEAP_TYPE::D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||
|
|
||
|
dtDescriptorHeap_ =
|
||
|
std::make_shared<DX12::DescriptorHeapAllocator>(graphics_, D3D12_DESCRIPTOR_HEAP_TYPE::D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
||
|
|
||
|
samplerDescriptorHeap_ =
|
||
|
std::make_shared<DX12::DescriptorHeapAllocator>(graphics_, D3D12_DESCRIPTOR_HEAP_TYPE::D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||
|
|
||
|
cbDescriptorHeap_ =
|
||
|
std::make_shared<DX12::DescriptorHeapAllocator>(graphics_, D3D12_DESCRIPTOR_HEAP_TYPE::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||
|
|
||
|
computeDescriptorHeap_ =
|
||
|
std::make_shared<DX12::DescriptorHeapAllocator>(graphics_, D3D12_DESCRIPTOR_HEAP_TYPE::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||
|
|
||
|
hr = graphics_->GetDevice()->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence_));
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
auto msg = (std::string("Error : ") + std::string(__FILE__) + " : " + std::to_string(__LINE__) + std::string(" : ") +
|
||
|
std::system_category().message(hr));
|
||
|
::LLGI::Log(::LLGI::LogType::Error, msg.c_str());
|
||
|
goto FAILED_EXIT;
|
||
|
}
|
||
|
fenceEvent_ = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||
|
return true;
|
||
|
|
||
|
FAILED_EXIT:;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void CommandListDX12::Begin()
|
||
|
{
|
||
|
commandAllocator_->Reset();
|
||
|
commandList_->Reset(commandAllocator_.get(), nullptr);
|
||
|
|
||
|
BeginInternal();
|
||
|
|
||
|
currentCommandList_ = commandList_.get();
|
||
|
|
||
|
CommandList::Begin();
|
||
|
}
|
||
|
|
||
|
void CommandListDX12::End()
|
||
|
{
|
||
|
assert(currentCommandList_ != nullptr);
|
||
|
currentCommandList_->Close();
|
||
|
currentCommandList_ = nullptr;
|
||
|
|
||
|
CommandList::End();
|
||
|
}
|
||
|
|
||
|
bool CommandListDX12::BeginWithPlatform(void* platformContextPtr)
|
||
|
{
|
||
|
auto ptr = reinterpret_cast<PlatformContextDX12*>(platformContextPtr);
|
||
|
|
||
|
BeginInternal();
|
||
|
|
||
|
currentCommandList_ = ptr->commandList;
|
||
|
|
||
|
return CommandList::BeginWithPlatform(platformContextPtr);
|
||
|
}
|
||
|
|
||
|
void CommandListDX12::EndWithPlatform()
|
||
|
{
|
||
|
assert(currentCommandList_ != nullptr);
|
||
|
currentCommandList_ = nullptr;
|
||
|
CommandList::EndWithPlatform();
|
||
|
}
|
||
|
|
||
|
void CommandListDX12::BeginRenderPass(RenderPass* renderPass)
|
||
|
{
|
||
|
assert(currentCommandList_ != nullptr);
|
||
|
|
||
|
SafeAddRef(renderPass);
|
||
|
renderPass_ = CreateSharedPtr((RenderPassDX12*)renderPass);
|
||
|
|
||
|
if (renderPass != nullptr)
|
||
|
{
|
||
|
// Set render target
|
||
|
if (!renderPass_->ReinitializeRenderTargetViews(this, rtDescriptorHeap_, dtDescriptorHeap_))
|
||
|
{
|
||
|
throw "Failed to start renderPass because of descriptors.";
|
||
|
}
|
||
|
|
||
|
currentCommandList_->OMSetRenderTargets(renderPass_->GetCount(), renderPass_->GetHandleRTV(), FALSE, renderPass_->GetHandleDSV());
|
||
|
|
||
|
// Reset scissor
|
||
|
D3D12_RECT rects[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
|
||
|
D3D12_VIEWPORT viewports[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
|
||
|
for (int i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT && i < renderPass_->GetCount(); i++)
|
||
|
{
|
||
|
auto size = (renderPass_->GetRenderTarget(i)->texture_ != nullptr) ? renderPass_->GetRenderTarget(i)->texture_->GetSizeAs2D()
|
||
|
: renderPass_->GetScreenSize();
|
||
|
rects[i].top = 0;
|
||
|
rects[i].left = 0;
|
||
|
rects[i].right = size.X;
|
||
|
rects[i].bottom = size.Y;
|
||
|
|
||
|
viewports[i].TopLeftX = 0.0f;
|
||
|
viewports[i].TopLeftY = 0.0f;
|
||
|
viewports[i].Width = static_cast<float>(size.X);
|
||
|
viewports[i].Height = static_cast<float>(size.Y);
|
||
|
viewports[i].MinDepth = 0.0f;
|
||
|
viewports[i].MaxDepth = 1.0f;
|
||
|
}
|
||
|
currentCommandList_->RSSetScissorRects(renderPass_->GetCount(), rects);
|
||
|
currentCommandList_->RSSetViewports(renderPass_->GetCount(), viewports);
|
||
|
|
||
|
if (renderPass_->GetIsColorCleared())
|
||
|
{
|
||
|
Clear(renderPass_->GetClearColor());
|
||
|
}
|
||
|
|
||
|
if (renderPass_->GetIsDepthCleared())
|
||
|
{
|
||
|
ClearDepth();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CommandList::BeginRenderPass(renderPass);
|
||
|
}
|
||
|
|
||
|
void CommandListDX12::EndRenderPass()
|
||
|
{
|
||
|
// Resolve MSAA
|
||
|
if (renderPass_ != nullptr && renderPass_->GetResolvedRenderTexture() != nullptr)
|
||
|
{
|
||
|
auto src = static_cast<TextureDX12*>(renderPass_->GetRenderTexture(0));
|
||
|
auto dst = static_cast<TextureDX12*>(renderPass_->GetResolvedRenderTexture());
|
||
|
|
||
|
// TODO : refactor
|
||
|
if (src->GetParameter().SampleCount <= 1)
|
||
|
{
|
||
|
Log(LogType::Error, "src SampleCount must be larger than 2.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (dst->GetParameter().SampleCount != 1)
|
||
|
{
|
||
|
Log(LogType::Error, "dst SampleCount must be 1.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
src->ResourceBarrior(currentCommandList_, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
|
||
|
dst->ResourceBarrior(currentCommandList_, D3D12_RESOURCE_STATE_RESOLVE_DEST);
|
||
|
|
||
|
currentCommandList_->ResolveSubresource(dst->Get(), 0, src->Get(), 0, dst->GetDXGIFormat());
|
||
|
}
|
||
|
|
||
|
if (renderPass_ != nullptr && renderPass_->GetResolvedDepthTexture() != nullptr)
|
||
|
{
|
||
|
auto src = static_cast<TextureDX12*>(renderPass_->GetDepthTexture());
|
||
|
auto dst = static_cast<TextureDX12*>(renderPass_->GetResolvedDepthTexture());
|
||
|
|
||
|
// TODO : refactor
|
||
|
if (src->GetParameter().SampleCount <= 1)
|
||
|
{
|
||
|
Log(LogType::Error, "src SampleCount must be larger than 2.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (dst->GetParameter().SampleCount != 1)
|
||
|
{
|
||
|
Log(LogType::Error, "dst SampleCount must be 1.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
src->ResourceBarrior(currentCommandList_, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
|
||
|
dst->ResourceBarrior(currentCommandList_, D3D12_RESOURCE_STATE_RESOLVE_DEST);
|
||
|
|
||
|
currentCommandList_->ResolveSubresource(dst->Get(), 0, src->Get(), 0, DirectX12::GetShaderResourceViewFormat(dst->GetDXGIFormat()));
|
||
|
}
|
||
|
|
||
|
renderPass_.reset();
|
||
|
CommandList::EndRenderPass();
|
||
|
}
|
||
|
|
||
|
void CommandListDX12::Draw(int32_t primitiveCount, int32_t instanceCount)
|
||
|
{
|
||
|
assert(currentCommandList_ != nullptr);
|
||
|
|
||
|
BindingVertexBuffer vb_;
|
||
|
BindingIndexBuffer ib_;
|
||
|
Buffer* cb = nullptr;
|
||
|
PipelineState* pip_ = nullptr;
|
||
|
|
||
|
bool isVBDirtied = false;
|
||
|
bool isIBDirtied = false;
|
||
|
bool isPipDirtied = false;
|
||
|
|
||
|
GetCurrentVertexBuffer(vb_, isVBDirtied);
|
||
|
GetCurrentIndexBuffer(ib_, isIBDirtied);
|
||
|
GetCurrentPipelineState(pip_, isPipDirtied);
|
||
|
|
||
|
assert(vb_.vertexBuffer != nullptr);
|
||
|
assert(ib_.indexBuffer != nullptr);
|
||
|
assert(pip_ != nullptr);
|
||
|
|
||
|
auto vb = static_cast<BufferDX12*>(vb_.vertexBuffer);
|
||
|
auto ib = static_cast<BufferDX12*>(ib_.indexBuffer);
|
||
|
auto pip = static_cast<PipelineStateDX12*>(pip_);
|
||
|
|
||
|
{
|
||
|
D3D12_VERTEX_BUFFER_VIEW vertexView;
|
||
|
vertexView.BufferLocation = vb->Get()->GetGPUVirtualAddress() + vb_.offset;
|
||
|
vertexView.StrideInBytes = vb_.stride;
|
||
|
vertexView.SizeInBytes = vb_.vertexBuffer->GetSize() - vb_.offset;
|
||
|
if (vb_.vertexBuffer != nullptr)
|
||
|
{
|
||
|
currentCommandList_->IASetVertexBuffers(0, 1, &vertexView);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ib != nullptr)
|
||
|
{
|
||
|
D3D12_INDEX_BUFFER_VIEW indexView;
|
||
|
indexView.BufferLocation = ib->Get()->GetGPUVirtualAddress() + ib_.offset;
|
||
|
indexView.SizeInBytes = ib->GetActualSize() - ib_.offset;
|
||
|
|
||
|
assert(ib_.stride == 2 || ib_.stride == 4);
|
||
|
indexView.Format = ib_.stride == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
|
||
|
currentCommandList_->IASetIndexBuffer(&indexView);
|
||
|
}
|
||
|
|
||
|
if (pip != nullptr)
|
||
|
{
|
||
|
currentCommandList_->SetGraphicsRootSignature(pip->GetRootSignature());
|
||
|
auto p = pip->GetPipelineState();
|
||
|
currentCommandList_->SetPipelineState(p);
|
||
|
currentCommandList_->OMSetStencilRef(pip->StencilRef);
|
||
|
}
|
||
|
|
||
|
// count descriptor
|
||
|
int32_t requiredCBDescriptorCount = 18;
|
||
|
int32_t requiredSamplerDescriptorCount = 1;
|
||
|
int32_t requiredComputeDescriptorCount = 0;
|
||
|
|
||
|
for (int stage_ind = 0; stage_ind < 2; stage_ind++)
|
||
|
{
|
||
|
for (size_t unit_ind = 0; unit_ind < currentTextures[stage_ind].size(); unit_ind++)
|
||
|
{
|
||
|
if (currentTextures[stage_ind][unit_ind].texture != nullptr)
|
||
|
{
|
||
|
requiredSamplerDescriptorCount = std::max(requiredSamplerDescriptorCount, static_cast<int32_t>(unit_ind) + 1);
|
||
|
}
|
||
|
|
||
|
BindingComputeBuffer compute;
|
||
|
GetCurrentComputeBuffer(static_cast<int32_t>(unit_ind), (ShaderStageType)stage_ind, compute);
|
||
|
if (compute.computeBuffer != nullptr)
|
||
|
{
|
||
|
requiredComputeDescriptorCount = std::max(requiredComputeDescriptorCount, static_cast<int32_t>(unit_ind) + 1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
requiredCBDescriptorCount += requiredComputeDescriptorCount;
|
||
|
|
||
|
ID3D12DescriptorHeap* heapSampler = nullptr;
|
||
|
ID3D12DescriptorHeap* heapConstant = nullptr;
|
||
|
|
||
|
std::array<D3D12_CPU_DESCRIPTOR_HANDLE, 32> cpuDescriptorHandleSampler;
|
||
|
std::array<D3D12_GPU_DESCRIPTOR_HANDLE, 32> gpuDescriptorHandleSampler;
|
||
|
std::array<D3D12_CPU_DESCRIPTOR_HANDLE, 32> cpuDescriptorHandleConstant;
|
||
|
std::array<D3D12_GPU_DESCRIPTOR_HANDLE, 32> gpuDescriptorHandleConstant;
|
||
|
|
||
|
if (!samplerDescriptorHeap_->Allocate(
|
||
|
heapSampler, cpuDescriptorHandleSampler, gpuDescriptorHandleSampler, requiredSamplerDescriptorCount))
|
||
|
{
|
||
|
Log(LogType::Error, "Failed to draw because of descriptors.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!cbDescriptorHeap_->Allocate(heapConstant, cpuDescriptorHandleConstant, gpuDescriptorHandleConstant, requiredCBDescriptorCount))
|
||
|
{
|
||
|
Log(LogType::Error, "Failed to draw because of descriptors.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// set using descriptor heaps
|
||
|
ID3D12DescriptorHeap* heaps[] = {
|
||
|
heapConstant,
|
||
|
heapSampler,
|
||
|
};
|
||
|
currentCommandList_->SetDescriptorHeaps(2, heaps);
|
||
|
|
||
|
// set descriptor tables
|
||
|
currentCommandList_->SetGraphicsRootDescriptorTable(0, gpuDescriptorHandleConstant[0]);
|
||
|
currentCommandList_->SetGraphicsRootDescriptorTable(1, gpuDescriptorHandleSampler[0]);
|
||
|
}
|
||
|
|
||
|
// constant buffer
|
||
|
{
|
||
|
for (int stage_ind = 0; stage_ind < 2; stage_ind++)
|
||
|
{
|
||
|
GetCurrentConstantBuffer(static_cast<ShaderStageType>(stage_ind), cb);
|
||
|
if (cb != nullptr)
|
||
|
{
|
||
|
auto _cb = static_cast<BufferDX12*>(cb);
|
||
|
D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {};
|
||
|
desc.BufferLocation = _cb->Get()->GetGPUVirtualAddress() + _cb->GetOffset();
|
||
|
desc.SizeInBytes = _cb->GetActualSize();
|
||
|
auto cpuHandle = cpuDescriptorHandleConstant[stage_ind];
|
||
|
graphics_->GetDevice()->CreateConstantBufferView(&desc, cpuHandle);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// set dummy values
|
||
|
D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {};
|
||
|
desc.BufferLocation = D3D12_GPU_VIRTUAL_ADDRESS();
|
||
|
desc.SizeInBytes = 0;
|
||
|
auto cpuHandle = cpuDescriptorHandleConstant[stage_ind];
|
||
|
graphics_->GetDevice()->CreateConstantBufferView(&desc, cpuHandle);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
for (int stage_ind = 0; stage_ind < 2; stage_ind++)
|
||
|
{
|
||
|
for (size_t unit_ind = 0; unit_ind < currentTextures[stage_ind].size(); unit_ind++)
|
||
|
{
|
||
|
if (currentTextures[stage_ind][unit_ind].texture != nullptr)
|
||
|
{
|
||
|
auto texture = static_cast<TextureDX12*>(currentTextures[stage_ind][unit_ind].texture);
|
||
|
auto wrapMode = currentTextures[stage_ind][unit_ind].wrapMode;
|
||
|
auto minMagFilter = currentTextures[stage_ind][unit_ind].minMagFilter;
|
||
|
|
||
|
// Make barrior to use a render target
|
||
|
if (texture->GetType() == TextureType::Render)
|
||
|
{
|
||
|
if (stage_ind == static_cast<int>(ShaderStageType::Pixel))
|
||
|
{
|
||
|
texture->ResourceBarrior(currentCommandList_, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
texture->ResourceBarrior(currentCommandList_, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// SRV
|
||
|
{
|
||
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||
|
|
||
|
if (texture->GetParameter().Dimension == 3)
|
||
|
{
|
||
|
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
|
||
|
srvDesc.Texture3D.MipLevels = 1;
|
||
|
srvDesc.Texture3D.MostDetailedMip = 0;
|
||
|
srvDesc.Texture3D.ResourceMinLODClamp = 0.0f;
|
||
|
}
|
||
|
else if ((texture->GetParameter().Usage & TextureUsageType::Array) != TextureUsageType::NoneFlag)
|
||
|
{
|
||
|
if (texture->GetParameter().SampleCount > 1)
|
||
|
{
|
||
|
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
|
||
|
}
|
||
|
srvDesc.Texture2DArray.ArraySize = texture->GetParameter().Size.Z;
|
||
|
srvDesc.Texture2DArray.FirstArraySlice = 0;
|
||
|
srvDesc.Texture2DArray.MipLevels = 1;
|
||
|
srvDesc.Texture2DArray.MostDetailedMip = 0;
|
||
|
srvDesc.Texture2DArray.PlaneSlice = 0;
|
||
|
srvDesc.Texture2DArray.ResourceMinLODClamp = 0.0f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (texture->GetParameter().SampleCount > 1)
|
||
|
{
|
||
|
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||
|
}
|
||
|
srvDesc.Texture2D.MipLevels = 1;
|
||
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
||
|
}
|
||
|
|
||
|
srvDesc.Format = DirectX12::GetShaderResourceViewFormat(texture->GetDXGIFormat());
|
||
|
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||
|
|
||
|
auto cpuHandle = cpuDescriptorHandleConstant[2 + static_cast<int32_t>(unit_ind)];
|
||
|
graphics_->GetDevice()->CreateShaderResourceView(texture->Get(), &srvDesc, cpuHandle);
|
||
|
}
|
||
|
|
||
|
// Sampler
|
||
|
{
|
||
|
D3D12_SAMPLER_DESC samplerDesc = {};
|
||
|
|
||
|
if (minMagFilter == TextureMinMagFilter::Nearest)
|
||
|
{
|
||
|
samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||
|
}
|
||
|
|
||
|
if (wrapMode == TextureWrapMode::Repeat)
|
||
|
{
|
||
|
samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||
|
samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||
|
samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||
|
samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||
|
samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||
|
}
|
||
|
samplerDesc.MipLODBias = 0;
|
||
|
samplerDesc.MaxAnisotropy = 0;
|
||
|
samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
||
|
samplerDesc.MinLOD = 0.0f;
|
||
|
samplerDesc.MaxLOD = D3D12_FLOAT32_MAX;
|
||
|
|
||
|
auto cpuHandle = cpuDescriptorHandleSampler[unit_ind];
|
||
|
graphics_->GetDevice()->CreateSampler(&samplerDesc, cpuHandle);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// UAV
|
||
|
for (int32_t unit_ind = 0; unit_ind < NumComputeBuffer; unit_ind++)
|
||
|
{
|
||
|
BindingComputeBuffer compute;
|
||
|
GetCurrentComputeBuffer(unit_ind, (ShaderStageType)stage_ind, compute);
|
||
|
|
||
|
if (compute.computeBuffer == nullptr)
|
||
|
continue;
|
||
|
|
||
|
auto computeBuffer = static_cast<BufferDX12*>(compute.computeBuffer);
|
||
|
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
|
||
|
|
||
|
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
|
||
|
uavDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||
|
|
||
|
uavDesc.Buffer.StructureByteStride = compute.stride;
|
||
|
uavDesc.Buffer.NumElements = computeBuffer->GetSize() / compute.stride;
|
||
|
uavDesc.Buffer.FirstElement = 0;
|
||
|
uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
|
||
|
|
||
|
auto cpuHandle = cpuDescriptorHandleConstant[18 + unit_ind];
|
||
|
graphics_->GetDevice()->CreateUnorderedAccessView(computeBuffer->Get(), nullptr, &uavDesc, cpuHandle);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// setup a topology (triangle)
|
||
|
|
||
|
int indexPerPrim = 0;
|
||
|
D3D_PRIMITIVE_TOPOLOGY topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||
|
|
||
|
if (pip_->Topology == TopologyType::Triangle)
|
||
|
{
|
||
|
indexPerPrim = 3;
|
||
|
topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||
|
}
|
||
|
else if (pip_->Topology == TopologyType::Line)
|
||
|
{
|
||
|
indexPerPrim = 2;
|
||
|
topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
|
||
|
}
|
||
|
else if (pip_->Topology == TopologyType::Point)
|
||
|
{
|
||
|
indexPerPrim = 1;
|
||
|
topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
assert(0);
|
||
|
}
|
||
|
|
||
|
currentCommandList_->IASetPrimitiveTopology(topology);
|
||
|
|
||
|
// draw polygon
|
||
|
currentCommandList_->DrawIndexedInstanced(primitiveCount * indexPerPrim, instanceCount, 0, 0, 0);
|
||
|
|
||
|
CommandList::Draw(primitiveCount, instanceCount);
|
||
|
}
|
||
|
|
||
|
void CommandListDX12::CopyTexture(Texture* src, Texture* dst)
|
||
|
{
|
||
|
auto srcTex = static_cast<TextureDX12*>(src);
|
||
|
CopyTexture(src, dst, {0, 0, 0}, {0, 0, 0}, srcTex->GetParameter().Size, 0, 0);
|
||
|
}
|
||
|
|
||
|
void CommandListDX12::CopyTexture(
|
||
|
Texture* src, Texture* dst, const Vec3I& srcPos, const Vec3I& dstPos, const Vec3I& size, int srcLayer, int dstLayer)
|
||
|
{
|
||
|
if (isInRenderPass_)
|
||
|
{
|
||
|
Log(LogType::Error, "Please call CopyTexture outside of RenderPass");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
auto srcTex = static_cast<TextureDX12*>(src);
|
||
|
auto dstTex = static_cast<TextureDX12*>(dst);
|
||
|
|
||
|
D3D12_TEXTURE_COPY_LOCATION srcLoc = {}, dstLoc = {};
|
||
|
|
||
|
srcLoc.pResource = srcTex->Get();
|
||
|
srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||
|
srcLoc.SubresourceIndex = srcLayer;
|
||
|
|
||
|
dstLoc.pResource = dstTex->Get();
|
||
|
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||
|
dstLoc.SubresourceIndex = dstLayer;
|
||
|
|
||
|
auto srcState = srcTex->GetState();
|
||
|
|
||
|
srcTex->ResourceBarrior(currentCommandList_, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||
|
dstTex->ResourceBarrior(currentCommandList_, D3D12_RESOURCE_STATE_COPY_DEST);
|
||
|
|
||
|
D3D12_BOX srcBox;
|
||
|
srcBox.left = srcPos[0];
|
||
|
srcBox.right = srcPos[0] + size[0];
|
||
|
srcBox.top = srcPos[1];
|
||
|
srcBox.bottom = srcPos[1] + size[1];
|
||
|
srcBox.front = srcPos[2];
|
||
|
srcBox.back = srcPos[2] + size[2];
|
||
|
|
||
|
currentCommandList_->CopyTextureRegion(&dstLoc, dstPos[0], dstPos[1], dstPos[2], &srcLoc, &srcBox);
|
||
|
|
||
|
dstTex->ResourceBarrior(currentCommandList_, D3D12_RESOURCE_STATE_GENERIC_READ);
|
||
|
srcTex->ResourceBarrior(currentCommandList_, srcState);
|
||
|
|
||
|
RegisterReferencedObject(src);
|
||
|
RegisterReferencedObject(dst);
|
||
|
}
|
||
|
|
||
|
void CommandListDX12::CopyBuffer(Buffer* src, Buffer* dst)
|
||
|
{
|
||
|
auto srcBuf = static_cast<BufferDX12*>(src);
|
||
|
auto dstBuf = static_cast<BufferDX12*>(dst);
|
||
|
|
||
|
auto srcResource = srcBuf->Get();
|
||
|
auto srcState = srcBuf->GetResourceState();
|
||
|
|
||
|
auto requireChangeSrcState = !BitwiseContains(srcState, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||
|
|
||
|
auto dstResource = dstBuf->Get();
|
||
|
auto dstState = dstBuf->GetResourceState();
|
||
|
|
||
|
auto requireChangeDstState = !BitwiseContains(dstState, D3D12_RESOURCE_STATE_COPY_DEST);
|
||
|
|
||
|
if (requireChangeSrcState)
|
||
|
{
|
||
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||
|
barrier.Transition.pResource = srcResource;
|
||
|
barrier.Transition.StateBefore = srcState;
|
||
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||
|
currentCommandList_->ResourceBarrier(1, &barrier);
|
||
|
}
|
||
|
|
||
|
if (requireChangeDstState)
|
||
|
{
|
||
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||
|
barrier.Transition.pResource = dstResource;
|
||
|
barrier.Transition.StateBefore = dstState;
|
||
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
|
||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||
|
currentCommandList_->ResourceBarrier(1, &barrier);
|
||
|
}
|
||
|
|
||
|
currentCommandList_->CopyBufferRegion(dstResource, dstBuf->GetOffset(), srcResource, srcBuf->GetOffset(), srcBuf->GetActualSize());
|
||
|
|
||
|
if (requireChangeSrcState)
|
||
|
{
|
||
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||
|
barrier.Transition.pResource = srcResource;
|
||
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||
|
barrier.Transition.StateAfter = srcState;
|
||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||
|
currentCommandList_->ResourceBarrier(1, &barrier);
|
||
|
}
|
||
|
|
||
|
if (requireChangeDstState)
|
||
|
{
|
||
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||
|
barrier.Transition.pResource = dstResource;
|
||
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||
|
barrier.Transition.StateAfter = dstState;
|
||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||
|
currentCommandList_->ResourceBarrier(1, &barrier);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CommandListDX12::BeginComputePass() {}
|
||
|
|
||
|
void CommandListDX12::EndComputePass() {}
|
||
|
|
||
|
void CommandListDX12::Dispatch(int32_t groupX, int32_t groupY, int32_t groupZ, int32_t threadX, int32_t threadY, int32_t threadZ)
|
||
|
{
|
||
|
assert(currentCommandList_ != nullptr);
|
||
|
PipelineState* pip_ = nullptr;
|
||
|
Buffer* cb = nullptr;
|
||
|
|
||
|
bool isPipDirtied = false;
|
||
|
|
||
|
GetCurrentPipelineState(pip_, isPipDirtied);
|
||
|
|
||
|
assert(pip_ != nullptr);
|
||
|
|
||
|
auto pip = static_cast<PipelineStateDX12*>(pip_);
|
||
|
|
||
|
if (pip != nullptr)
|
||
|
{
|
||
|
currentCommandList_->SetComputeRootSignature(pip->GetComputeRootSignature());
|
||
|
auto p = pip->GetComputePipelineState();
|
||
|
currentCommandList_->SetPipelineState(p);
|
||
|
}
|
||
|
|
||
|
int32_t requiredCBDescriptorCount = 1 + NumComputeBuffer;
|
||
|
|
||
|
ID3D12DescriptorHeap* heapConstant = nullptr;
|
||
|
|
||
|
std::array<D3D12_CPU_DESCRIPTOR_HANDLE, 32> cpuDescriptorHandleConstant;
|
||
|
std::array<D3D12_GPU_DESCRIPTOR_HANDLE, 32> gpuDescriptorHandleConstant;
|
||
|
|
||
|
if (!cbDescriptorHeap_->Allocate(heapConstant, cpuDescriptorHandleConstant, gpuDescriptorHandleConstant, requiredCBDescriptorCount))
|
||
|
{
|
||
|
Log(LogType::Error, "Failed to draw because of descriptors.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// set using descriptor heaps
|
||
|
ID3D12DescriptorHeap* heaps[] = {
|
||
|
heapConstant,
|
||
|
};
|
||
|
currentCommandList_->SetDescriptorHeaps(1, heaps);
|
||
|
|
||
|
// set descriptor tables
|
||
|
currentCommandList_->SetComputeRootDescriptorTable(0, gpuDescriptorHandleConstant[0]);
|
||
|
}
|
||
|
|
||
|
int stage_ind = static_cast<int>(ShaderStageType::Compute);
|
||
|
|
||
|
// constant buffer
|
||
|
{
|
||
|
GetCurrentConstantBuffer(static_cast<ShaderStageType>(stage_ind), cb);
|
||
|
if (cb != nullptr)
|
||
|
{
|
||
|
auto _cb = static_cast<BufferDX12*>(cb);
|
||
|
D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {};
|
||
|
desc.BufferLocation = _cb->Get()->GetGPUVirtualAddress() + _cb->GetOffset();
|
||
|
desc.SizeInBytes = _cb->GetActualSize();
|
||
|
auto cpuHandle = cpuDescriptorHandleConstant[0];
|
||
|
graphics_->GetDevice()->CreateConstantBufferView(&desc, cpuHandle);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// set dummy values
|
||
|
D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {};
|
||
|
desc.BufferLocation = D3D12_GPU_VIRTUAL_ADDRESS();
|
||
|
desc.SizeInBytes = 0;
|
||
|
auto cpuHandle = cpuDescriptorHandleConstant[0];
|
||
|
graphics_->GetDevice()->CreateConstantBufferView(&desc, cpuHandle);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// UAV
|
||
|
for (int32_t unit_ind = 0; unit_ind < NumComputeBuffer; unit_ind++)
|
||
|
{
|
||
|
BindingComputeBuffer compute;
|
||
|
GetCurrentComputeBuffer(unit_ind, ShaderStageType::Compute, compute);
|
||
|
|
||
|
if (compute.computeBuffer == nullptr)
|
||
|
continue;
|
||
|
|
||
|
auto computeBuffer = static_cast<BufferDX12*>(compute.computeBuffer);
|
||
|
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
|
||
|
|
||
|
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
|
||
|
uavDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||
|
|
||
|
uavDesc.Buffer.StructureByteStride = compute.stride;
|
||
|
uavDesc.Buffer.NumElements = computeBuffer->GetSize() / compute.stride;
|
||
|
uavDesc.Buffer.FirstElement = 0;
|
||
|
uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
|
||
|
|
||
|
auto cpuHandle = cpuDescriptorHandleConstant[1 + unit_ind];
|
||
|
graphics_->GetDevice()->CreateUnorderedAccessView(computeBuffer->Get(), nullptr, &uavDesc, cpuHandle);
|
||
|
}
|
||
|
|
||
|
currentCommandList_->Dispatch(groupX, groupY, groupZ);
|
||
|
|
||
|
CommandList::Dispatch(groupX, groupY, groupZ, threadX, threadY, threadZ);
|
||
|
}
|
||
|
|
||
|
void CommandListDX12::Clear(const Color8& color)
|
||
|
{
|
||
|
assert(currentCommandList_ != nullptr);
|
||
|
|
||
|
auto rt = renderPass_;
|
||
|
if (rt == nullptr)
|
||
|
return;
|
||
|
|
||
|
float color_[] = {color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f};
|
||
|
|
||
|
auto handle = rt->GetHandleRTV();
|
||
|
for (int i = 0; i < rt->GetCount(); i++)
|
||
|
{
|
||
|
currentCommandList_->ClearRenderTargetView(handle[i], color_, 0, nullptr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CommandListDX12::ClearDepth()
|
||
|
{
|
||
|
assert(currentCommandList_ != nullptr);
|
||
|
|
||
|
auto rt = renderPass_;
|
||
|
if (rt == nullptr)
|
||
|
return;
|
||
|
|
||
|
if (!rt->GetHasDepthTexture())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
auto handle = rt->GetHandleDSV();
|
||
|
for (int i = 0; i < rt->GetCount(); i++)
|
||
|
{
|
||
|
currentCommandList_->ClearDepthStencilView(handle[i], D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ID3D12GraphicsCommandList* CommandListDX12::GetCommandList() const { return commandList_.get(); }
|
||
|
|
||
|
ID3D12Fence* CommandListDX12::GetFence() const { return fence_; }
|
||
|
|
||
|
UINT64 CommandListDX12::GetAndIncFenceValue()
|
||
|
{
|
||
|
auto ret = fenceValue_;
|
||
|
fenceValue_ += 1;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void CommandListDX12::WaitUntilCompleted()
|
||
|
{
|
||
|
|
||
|
if (fence_->GetCompletedValue() < fenceValue_ - 1)
|
||
|
{
|
||
|
auto hr = fence_->SetEventOnCompletion(fenceValue_ - 1, fenceEvent_);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
WaitForSingleObject(fenceEvent_, INFINITE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace LLGI
|