verus/RendererDirect3D12/src/CGI/GeometryD3D12.cpp

328 lines
9.9 KiB
C++

#include "stdafx.h"
using namespace verus;
using namespace verus::CGI;
GeometryD3D12::GeometryD3D12()
{
VERUS_ZERO_MEM(_indexBufferView);
}
GeometryD3D12::~GeometryD3D12()
{
Done();
}
void GeometryD3D12::Init(RcGeometryDesc desc)
{
VERUS_INIT();
_dynBindingsMask = desc._dynBindingsMask;
_32BitIndices = desc._32BitIndices;
_vInputElementDesc.reserve(GetVertexInputAttrDescCount(desc._pVertexInputAttrDesc));
int i = 0;
while (desc._pVertexInputAttrDesc[i]._offset >= 0)
{
int binding = desc._pVertexInputAttrDesc[i]._binding;
D3D12_INPUT_CLASSIFICATION inputClassification = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
UINT instanceDataStepRate = 0;
if (binding < 0)
{
binding = -binding;
_instBindingsMask |= (1 << binding);
inputClassification = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
instanceDataStepRate = 1;
}
D3D12_INPUT_ELEMENT_DESC ieDesc =
{
ToNativeSemanticName(desc._pVertexInputAttrDesc[i]._usage),
static_cast<UINT>(desc._pVertexInputAttrDesc[i]._usageIndex),
ToNativeFormat(desc._pVertexInputAttrDesc[i]._usage, desc._pVertexInputAttrDesc[i]._type, desc._pVertexInputAttrDesc[i]._components),
static_cast<UINT>(binding),
static_cast<UINT>(desc._pVertexInputAttrDesc[i]._offset),
inputClassification,
instanceDataStepRate
};
_vInputElementDesc.push_back(ieDesc);
i++;
}
_vStrides.reserve(GetBindingCount(desc._pVertexInputAttrDesc));
i = 0;
while (desc._pStrides[i] > 0)
{
_vStrides.push_back(desc._pStrides[i]);
i++;
}
_vVertexBuffers.reserve(4);
_vStagingVertexBuffers.reserve(4);
}
void GeometryD3D12::Done()
{
ForceScheduled();
VERUS_SMART_RELEASE(_indexBuffer._pMaAllocation);
VERUS_COM_RELEASE_CHECK(_indexBuffer._pBuffer.Get());
_indexBuffer._pBuffer.Reset();
for (auto& x : _vVertexBuffers)
{
VERUS_SMART_RELEASE(x._pMaAllocation);
VERUS_COM_RELEASE_CHECK(x._pBuffer.Get());
x._pBuffer.Reset();
}
_vVertexBuffers.clear();
VERUS_DONE(GeometryD3D12);
}
void GeometryD3D12::CreateVertexBuffer(int count, int binding)
{
VERUS_QREF_RENDERER_D3D12;
HRESULT hr = 0;
if (_vVertexBuffers.size() <= binding)
_vVertexBuffers.resize(binding + 1);
auto& vb = _vVertexBuffers[binding];
const int elementSize = _vStrides[binding];
vb._bufferSize = count * elementSize;
if (((_instBindingsMask | _dynBindingsMask) >> binding) & 0x1)
{
D3D12MA::ALLOCATION_DESC allocDesc = {};
allocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
if (FAILED(hr = pRendererD3D12->GetMaAllocator()->CreateResource(
&allocDesc,
&CD3DX12_RESOURCE_DESC::Buffer(vb._bufferSize * BaseRenderer::s_ringBufferSize),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
&vb._pMaAllocation,
IID_PPV_ARGS(&vb._pBuffer))))
throw VERUS_RUNTIME_ERROR << "CreateResource(D3D12_HEAP_TYPE_UPLOAD), hr=" << VERUS_HR(hr);
VERUS_FOR(i, BaseRenderer::s_ringBufferSize)
{
vb._bufferView[i].BufferLocation = vb._pBuffer->GetGPUVirtualAddress() + i * vb._bufferSize;
vb._bufferView[i].SizeInBytes = Utils::Cast32(vb._bufferSize);
vb._bufferView[i].StrideInBytes = elementSize;
}
}
else
{
D3D12MA::ALLOCATION_DESC allocDesc = {};
allocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
if (FAILED(hr = pRendererD3D12->GetMaAllocator()->CreateResource(
&allocDesc,
&CD3DX12_RESOURCE_DESC::Buffer(vb._bufferSize),
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
&vb._pMaAllocation,
IID_PPV_ARGS(&vb._pBuffer))))
throw VERUS_RUNTIME_ERROR << "CreateResource(D3D12_HEAP_TYPE_DEFAULT), hr=" << VERUS_HR(hr);
vb._bufferView[0].BufferLocation = vb._pBuffer->GetGPUVirtualAddress();
vb._bufferView[0].SizeInBytes = Utils::Cast32(vb._bufferSize);
vb._bufferView[0].StrideInBytes = elementSize;
}
}
void GeometryD3D12::UpdateVertexBuffer(const void* p, int binding, PBaseCommandBuffer pCB)
{
VERUS_QREF_RENDERER;
VERUS_QREF_RENDERER_D3D12;
HRESULT hr = 0;
if (((_instBindingsMask | _dynBindingsMask) >> binding) & 0x1)
{
auto& vb = _vVertexBuffers[binding];
CD3DX12_RANGE readRange(0, 0);
void* pData = nullptr;
if (FAILED(hr = vb._pBuffer->Map(0, &readRange, &pData)))
throw VERUS_RUNTIME_ERROR << "Map(), hr=" << VERUS_HR(hr);
BYTE* pMappedData = static_cast<BYTE*>(pData) + pRendererD3D12->GetRingBufferIndex() * vb._bufferSize;
memcpy(pMappedData, p, vb._bufferSize);
vb._pBuffer->Unmap(0, nullptr);
}
else
{
if (_vStagingVertexBuffers.size() <= binding)
_vStagingVertexBuffers.resize(binding + 1);
bool revertState = true;
auto& vb = _vVertexBuffers[binding];
auto& svb = _vStagingVertexBuffers[binding];
if (!svb._pBuffer)
{
revertState = false;
D3D12MA::ALLOCATION_DESC allocDesc = {};
allocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
if (FAILED(hr = pRendererD3D12->GetMaAllocator()->CreateResource(
&allocDesc,
&CD3DX12_RESOURCE_DESC::Buffer(vb._bufferSize),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
&svb._pMaAllocation,
IID_PPV_ARGS(&svb._pBuffer))))
throw VERUS_RUNTIME_ERROR << "CreateResource(D3D12_HEAP_TYPE_UPLOAD), hr=" << VERUS_HR(hr);
}
if (!pCB)
pCB = renderer.GetCommandBuffer().Get();
auto pCmdList = static_cast<PCommandBufferD3D12>(pCB)->GetD3DGraphicsCommandList();
if (revertState)
{
const CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
vb._pBuffer.Get(), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, D3D12_RESOURCE_STATE_COPY_DEST);
pCmdList->ResourceBarrier(1, &barrier);
}
D3D12_SUBRESOURCE_DATA sd = {};
sd.pData = p;
sd.RowPitch = vb._bufferSize;
sd.SlicePitch = sd.RowPitch;
UpdateSubresources<1>(pCmdList,
vb._pBuffer.Get(),
svb._pBuffer.Get(),
0, 0, 1, &sd);
const CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
vb._pBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
pCmdList->ResourceBarrier(1, &barrier);
Schedule();
}
}
void GeometryD3D12::CreateIndexBuffer(int count)
{
VERUS_QREF_RENDERER_D3D12;
HRESULT hr = 0;
const int elementSize = _32BitIndices ? sizeof(UINT32) : sizeof(UINT16);
_indexBuffer._bufferSize = count * elementSize;
D3D12MA::ALLOCATION_DESC allocDesc = {};
allocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
if (FAILED(hr = pRendererD3D12->GetMaAllocator()->CreateResource(
&allocDesc,
&CD3DX12_RESOURCE_DESC::Buffer(_indexBuffer._bufferSize),
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
&_indexBuffer._pMaAllocation,
IID_PPV_ARGS(&_indexBuffer._pBuffer))))
throw VERUS_RUNTIME_ERROR << "CreateResource(D3D12_HEAP_TYPE_DEFAULT), hr=" << VERUS_HR(hr);
_indexBufferView.BufferLocation = _indexBuffer._pBuffer->GetGPUVirtualAddress();
_indexBufferView.SizeInBytes = Utils::Cast32(_indexBuffer._bufferSize);
_indexBufferView.Format = _32BitIndices ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT;
}
void GeometryD3D12::UpdateIndexBuffer(const void* p, PBaseCommandBuffer pCB)
{
VERUS_QREF_RENDERER;
VERUS_QREF_RENDERER_D3D12;
HRESULT hr = 0;
bool revertState = true;
if (!_stagingIndexBuffer._pBuffer)
{
revertState = false;
D3D12MA::ALLOCATION_DESC allocDesc = {};
allocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
if (FAILED(hr = pRendererD3D12->GetMaAllocator()->CreateResource(
&allocDesc,
&CD3DX12_RESOURCE_DESC::Buffer(_indexBuffer._bufferSize),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
&_stagingIndexBuffer._pMaAllocation,
IID_PPV_ARGS(&_stagingIndexBuffer._pBuffer))))
throw VERUS_RUNTIME_ERROR << "CreateResource(D3D12_HEAP_TYPE_UPLOAD), hr=" << VERUS_HR(hr);
}
if (!pCB)
pCB = renderer.GetCommandBuffer().Get();
auto pCmdList = static_cast<PCommandBufferD3D12>(pCB)->GetD3DGraphicsCommandList();
if (revertState)
{
const CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
_indexBuffer._pBuffer.Get(), D3D12_RESOURCE_STATE_INDEX_BUFFER, D3D12_RESOURCE_STATE_COPY_DEST);
pCmdList->ResourceBarrier(1, &barrier);
}
D3D12_SUBRESOURCE_DATA sd = {};
sd.pData = p;
sd.RowPitch = _indexBuffer._bufferSize;
sd.SlicePitch = sd.RowPitch;
UpdateSubresources<1>(pCmdList,
_indexBuffer._pBuffer.Get(),
_stagingIndexBuffer._pBuffer.Get(),
0, 0, 1, &sd);
const CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
_indexBuffer._pBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER);
pCmdList->ResourceBarrier(1, &barrier);
Schedule();
}
Continue GeometryD3D12::Scheduled_Update()
{
if (!IsScheduledAllowed())
return Continue::yes;
VERUS_SMART_RELEASE(_stagingIndexBuffer._pMaAllocation);
VERUS_COM_RELEASE_CHECK(_stagingIndexBuffer._pBuffer.Get());
_stagingIndexBuffer._pBuffer.Reset();
for (auto& x : _vStagingVertexBuffers)
{
VERUS_SMART_RELEASE(x._pMaAllocation);
VERUS_COM_RELEASE_CHECK(x._pBuffer.Get());
x._pBuffer.Reset();
}
_vStagingVertexBuffers.clear();
return Continue::no;
}
D3D12_INPUT_LAYOUT_DESC GeometryD3D12::GetD3DInputLayoutDesc(UINT32 bindingsFilter, Vector<D3D12_INPUT_ELEMENT_DESC>& vInputElementDesc) const
{
if (UINT32_MAX == bindingsFilter)
return { _vInputElementDesc.data(), Utils::Cast32(_vInputElementDesc.size()) };
uint32_t replaceBinding[VERUS_MAX_VB] = {}; // For bindings compaction.
int binding = 0;
VERUS_FOR(i, VERUS_MAX_VB)
{
replaceBinding[i] = binding;
if ((bindingsFilter >> i) & 0x1)
binding++;
}
vInputElementDesc.reserve(_vInputElementDesc.size());
for (const auto& x : _vInputElementDesc)
{
if ((bindingsFilter >> x.InputSlot) & 0x1)
{
vInputElementDesc.push_back(x);
vInputElementDesc.back().InputSlot = replaceBinding[x.InputSlot];
}
}
return { vInputElementDesc.data(), Utils::Cast32(vInputElementDesc.size()) };
}
const D3D12_VERTEX_BUFFER_VIEW* GeometryD3D12::GetD3DVertexBufferView(int binding) const
{
if (((_instBindingsMask | _dynBindingsMask) >> binding) & 0x1)
{
VERUS_QREF_RENDERER_D3D12;
return &_vVertexBuffers[binding]._bufferView[pRendererD3D12->GetRingBufferIndex()];
}
else
return &_vVertexBuffers[binding]._bufferView[0];
}
const D3D12_INDEX_BUFFER_VIEW* GeometryD3D12::GetD3DIndexBufferView() const
{
return &_indexBufferView;
}