verus/RendererDirect3D11/src/CGI/GeometryD3D11.cpp

231 lines
6.9 KiB
C++

// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
#include "pch.h"
using namespace verus;
using namespace verus::CGI;
GeometryD3D11::GeometryD3D11()
{
}
GeometryD3D11::~GeometryD3D11()
{
Done();
}
void GeometryD3D11::Init(RcGeometryDesc desc)
{
VERUS_INIT();
_name = desc._name;
_dynBindingsMask = desc._dynBindingsMask;
_32BitIndices = desc._32BitIndices;
_vInputElementDescs.reserve(GetVertexInputAttrDescCount(desc._pVertexInputAttrDesc));
int i = 0;
while (desc._pVertexInputAttrDesc[i]._offset >= 0)
{
int binding = desc._pVertexInputAttrDesc[i]._binding;
D3D11_INPUT_CLASSIFICATION inputClassification = D3D11_INPUT_PER_VERTEX_DATA;
UINT instanceDataStepRate = 0;
if (binding < 0)
{
binding = -binding;
_instBindingsMask |= (1 << binding);
inputClassification = D3D11_INPUT_PER_INSTANCE_DATA;
instanceDataStepRate = 1;
}
D3D11_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
};
_vInputElementDescs.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);
}
void GeometryD3D11::Done()
{
ForceScheduled();
_indexBuffer._pBuffer.Reset();
for (auto& x : _vVertexBuffers)
x._pBuffer.Reset();
_vVertexBuffers.clear();
VERUS_DONE(GeometryD3D11);
}
void GeometryD3D11::CreateVertexBuffer(int count, int binding)
{
VERUS_QREF_RENDERER_D3D11;
HRESULT hr = 0;
if (_vVertexBuffers.size() <= binding)
_vVertexBuffers.resize(binding + 1);
auto& vb = _vVertexBuffers[binding];
const int elementSize = _vStrides[binding];
vb._bufferSize = count * elementSize;
D3D11_BUFFER_DESC vbDesc = {};
vbDesc.ByteWidth = Utils::Cast32(vb._bufferSize);
vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
if (((_instBindingsMask | _dynBindingsMask) >> binding) & 0x1)
{
vbDesc.Usage = D3D11_USAGE_DYNAMIC;
vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateBuffer(&vbDesc, nullptr, &vb._pBuffer)))
throw VERUS_RUNTIME_ERROR << "CreateBuffer(D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC), " << VERUS_HR(hr);
SetDebugObjectName(vb._pBuffer.Get(), _C(_name + " (Dynamic VB, " + std::to_string(binding) + ")"));
}
else
{
if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateBuffer(&vbDesc, nullptr, &vb._pBuffer)))
throw VERUS_RUNTIME_ERROR << "CreateBuffer(D3D11_BIND_VERTEX_BUFFER), " << VERUS_HR(hr);
SetDebugObjectName(vb._pBuffer.Get(), _C(_name + " (VB, " + std::to_string(binding) + ")"));
}
}
void GeometryD3D11::UpdateVertexBuffer(const void* p, int binding, PBaseCommandBuffer pCB, INT64 size, INT64 offset)
{
VERUS_QREF_RENDERER;
HRESULT hr = 0;
if (!pCB)
pCB = renderer.GetCommandBuffer().Get();
auto pDeviceContext = static_cast<PCommandBufferD3D11>(pCB)->GetD3DDeviceContext();
if (((_instBindingsMask | _dynBindingsMask) >> binding) & 0x1)
{
auto& vb = _vVertexBuffers[binding];
const int elementSize = _vStrides[binding];
size = size ? size * elementSize : vb._bufferSize;
const D3D11_MAP mapType = (size == vb._bufferSize) ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE;
D3D11_MAPPED_SUBRESOURCE ms = {};
if (FAILED(hr = pDeviceContext->Map(vb._pBuffer.Get(), 0, mapType, 0, &ms)))
throw VERUS_RUNTIME_ERROR << "Map(); hr=" << VERUS_HR(hr);
BYTE* pMappedData = static_cast<BYTE*>(ms.pData);
memcpy(pMappedData + offset * elementSize, p, size);
pDeviceContext->Unmap(vb._pBuffer.Get(), 0);
}
else
{
auto& vb = _vVertexBuffers[binding];
pDeviceContext->UpdateSubresource(
vb._pBuffer.Get(), 0, nullptr,
p, 0, 0);
}
}
void GeometryD3D11::CreateIndexBuffer(int count)
{
VERUS_QREF_RENDERER_D3D11;
HRESULT hr = 0;
const int elementSize = _32BitIndices ? sizeof(UINT32) : sizeof(UINT16);
_indexBuffer._bufferSize = count * elementSize;
D3D11_BUFFER_DESC ibDesc = {};
ibDesc.ByteWidth = Utils::Cast32(_indexBuffer._bufferSize);
ibDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
if ((_dynBindingsMask >> 31) & 0x1)
{
ibDesc.Usage = D3D11_USAGE_DYNAMIC;
ibDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateBuffer(&ibDesc, nullptr, &_indexBuffer._pBuffer)))
throw VERUS_RUNTIME_ERROR << "CreateBuffer(D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC), " << VERUS_HR(hr);
SetDebugObjectName(_indexBuffer._pBuffer.Get(), _C(_name + " (Dynamic IB)"));
}
else
{
if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateBuffer(&ibDesc, nullptr, &_indexBuffer._pBuffer)))
throw VERUS_RUNTIME_ERROR << "CreateBuffer(D3D11_BIND_VERTEX_BUFFER), " << VERUS_HR(hr);
SetDebugObjectName(_indexBuffer._pBuffer.Get(), _C(_name + " (IB)"));
}
}
void GeometryD3D11::UpdateIndexBuffer(const void* p, PBaseCommandBuffer pCB, INT64 size, INT64 offset)
{
VERUS_QREF_RENDERER;
HRESULT hr = 0;
if (!pCB)
pCB = renderer.GetCommandBuffer().Get();
auto pDeviceContext = static_cast<PCommandBufferD3D11>(pCB)->GetD3DDeviceContext();
if ((_dynBindingsMask >> 31) & 0x1)
{
const int elementSize = _32BitIndices ? sizeof(UINT32) : sizeof(UINT16);
size = size ? size * elementSize : _indexBuffer._bufferSize;
const D3D11_MAP mapType = (size == _indexBuffer._bufferSize) ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE;
D3D11_MAPPED_SUBRESOURCE ms = {};
if (FAILED(hr = pDeviceContext->Map(_indexBuffer._pBuffer.Get(), 0, mapType, 0, &ms)))
throw VERUS_RUNTIME_ERROR << "Map(); hr=" << VERUS_HR(hr);
BYTE* pMappedData = static_cast<BYTE*>(ms.pData);
memcpy(pMappedData + offset * elementSize, p, size);
pDeviceContext->Unmap(_indexBuffer._pBuffer.Get(), 0);
}
else
{
pDeviceContext->UpdateSubresource(
_indexBuffer._pBuffer.Get(), 0, nullptr,
p, 0, 0);
}
}
Continue GeometryD3D11::Scheduled_Update()
{
return Continue::yes;
}
void GeometryD3D11::GetD3DInputElementDescs(UINT32 bindingsFilter, Vector<D3D11_INPUT_ELEMENT_DESC>& vInputElementDescs) const
{
UINT replaceBinding[VERUS_MAX_VB] = {}; // For bindings compaction.
UINT binding = 0;
VERUS_FOR(i, VERUS_MAX_VB)
{
replaceBinding[i] = binding;
if ((bindingsFilter >> i) & 0x1)
binding++;
}
vInputElementDescs.reserve(_vInputElementDescs.size());
for (const auto& x : _vInputElementDescs)
{
if ((bindingsFilter >> x.InputSlot) & 0x1)
{
vInputElementDescs.push_back(x);
vInputElementDescs.back().InputSlot = replaceBinding[x.InputSlot];
}
}
}
ID3D11Buffer* GeometryD3D11::GetD3DVertexBuffer(int binding) const
{
return _vVertexBuffers[binding]._pBuffer.Get();
}
ID3D11Buffer* GeometryD3D11::GetD3DIndexBuffer() const
{
return _indexBuffer._pBuffer.Get();
}