1#include "BuffersD3D12.h"
3#include "Foundation/Logging/Logger.h"
5#include "EffectsD3D12.h"
6#include "FormatsD3D12.h"
7#include "GraphicsDeviceD3D12.h"
18 const DXGI_FORMAT IndexFormats[] = {
23 LPCSTR Semantics[] = {
35Cogs::BufferPage::BufferPage(BufferContext & context,
size_t pageSize)
37 CD3DX12_HEAP_PROPERTIES heapProperties(context.heapType);
38 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(context.elementSize * pageSize);
40 auto hr = context.device->CreateCommittedResource(
44 context.resourceState,
46 IID_PPV_ARGS(buffer.internalPointer()));
54 buffer->Map(0,
nullptr,
reinterpret_cast<void **
>(&mappedRegion));
55 mappedGpuRegion = buffer->GetGPUVirtualAddress();
58 storage.resize(
sizeof(PoolBuffer) * pageSize);
60 auto head =
reinterpret_cast<PoolBuffer *
>(storage.data());
63 for (
size_t i = 0; i < pageSize; ++i) {
64 PoolBuffer * block = head + i;
66 auto offset = i * context.elementSize;
67 block->mappedRegion = mappedRegion + offset;
68 block->mappedGpuRegion = mappedGpuRegion + offset;
69 block->resource = buffer;
70 block->pool = context.pool;
71 block->offset = offset;
73 block->next = block + 1;
76 (head + pageSize - 1)->next =
nullptr;
79void Cogs::BuffersD3D12::initialize(
struct GraphicsDeviceD3D12 * graphicsDevice)
81 this->graphicsDevice = graphicsDevice;
82 this->device = graphicsDevice->device;
83 this->effects = &graphicsDevice->effects;
85 bufferPool256.initialize(device, 1024, 256, 128);
86 bufferPool1024.initialize(device, 1024, 1024, 128);
93 const size_t vertexSize = getSize(vertexFormat);
94 const size_t size = count * vertexSize;
96 allocateBuffer(buffer, size, vertexData);
101 buffer.vertexBufferView.BufferLocation = buffer.resource ? buffer.resource->GetGPUVirtualAddress() : buffer.pooledResource->mappedGpuRegion;
102 buffer.vertexBufferView.StrideInBytes =
static_cast<UINT
>(vertexSize);
103 buffer.vertexBufferView.SizeInBytes =
static_cast<UINT
>(size);
107 auto formatHandle = createVertexFormat(vertexFormat.
elements.data(), vertexFormat.
elements.size());
109 buffer.vertexFormat = getVertexFormat(formatHandle);
118 return loadVertexBuffer(vertexData, count, *VertexFormats::getVertexFormat(vertexFormatHandle));
123 releaseBufferInternal(vertexBufferHandle);
130 const size_t size = count * indexSize;
132 allocateBuffer(buffer, size, indexData);
134 buffer.indexBufferView.BufferLocation = buffer.resource ? buffer.resource->GetGPUVirtualAddress() : buffer.pooledResource->mappedGpuRegion;
135 buffer.indexBufferView.SizeInBytes =
static_cast<UINT
>(size);
136 buffer.indexBufferView.Format = indexSize ==
sizeof(UINT) ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT;
137 buffer.count = count;
147 releaseBufferInternal(indexBufferHandle);
154 auto & inputElements = inputLayout.inputElements;
155 auto & inputElementCount = inputLayout.inputElementCount;
157 for (
size_t i = 0; i < count; ++i) {
158 const VertexFormat & vertexFormat = *VertexFormats::getVertexFormat(vertexFormats[i]);
159 const size_t numElements = vertexFormat.
elements.size();
161 for (
size_t j = 0; j < numElements; ++j) {
164 if (inputElementCount >= D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT) {
165 LOG_ERROR(logger,
"Input element count exceeds limit set by D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT.");
172 assert(format != DXGI_FORMAT_UNKNOWN &&
"Unknown data format. Check input vertex formats.");
175 D3D12_INPUT_ELEMENT_DESC elementDescription = {
176 Direct3D12::Semantics[(int)element.
semantic],
179 static_cast<UINT
>(i),
180 static_cast<UINT
>(element.
offset),
181 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
185 inputElements[inputElementCount++] = elementDescription;
188 for (uint32_t m = 0; m < 4; ++m) {
189 D3D12_INPUT_ELEMENT_DESC elementDescription = {
190 Direct3D12::Semantics[(int)element.
semantic],
192 DXGI_FORMAT_R32G32B32A32_FLOAT,
193 static_cast<UINT
>(i),
194 static_cast<UINT
>(element.
offset + m * 4 *
sizeof(float)),
195 D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA,
199 inputElements[inputElementCount++] = elementDescription;
202 D3D12_INPUT_ELEMENT_DESC elementDescription = {
203 Direct3D12::Semantics[(int)element.
semantic],
206 static_cast<UINT
>(i),
207 static_cast<UINT
>(element.
offset),
208 D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA,
212 inputElements[inputElementCount++] = elementDescription;
218 return inputLayouts.addResource(inputLayout);
223 inputLayouts.removeResource(inputLayoutHandle);
229 buffer.bindFlags = bindFlags;
233 allocateBuffer(buffer, size, data);
235 if (buffer.pooledResource) {
236 buffer.cbvDesc.BufferLocation = buffer.pooledResource->mappedGpuRegion;
238 buffer.cbvDesc.BufferLocation = buffer.resource->GetGPUVirtualAddress();
240 buffer.cbvDesc.SizeInBytes =
static_cast<UINT
>(size);
241 buffer.cbvDesc.SizeInBytes = (buffer.cbvDesc.SizeInBytes + 255) & ~255;
244 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
246 device->CreateCommittedResource(
247 &defaultHeapProperties,
248 D3D12_HEAP_FLAG_NONE,
250 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
252 IID_PPV_ARGS(buffer.resource.internalPointer()));
254 buffer.usage = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
257 allocateBuffer(buffer.uploadResource, size, data);
260 buffer.uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
261 buffer.uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
262 buffer.uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
263 buffer.uavDesc.Buffer.FirstElement = 0;
264 buffer.uavDesc.Buffer.NumElements =
static_cast<uint32_t
>(size) / 4;
265 buffer.uavDesc.Buffer.StructureByteStride = 0;
266 buffer.uavDesc.Buffer.CounterOffsetInBytes = 0;
269 buffer.srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
270 buffer.srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
271 buffer.srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
272 buffer.srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
273 buffer.srvDesc.Buffer.FirstElement = 0;
274 buffer.srvDesc.Buffer.NumElements =
static_cast<uint32_t
>(size) / 4;
275 buffer.srvDesc.Buffer.StructureByteStride = 0;
278 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
280 device->CreateCommittedResource(
281 &defaultHeapProperties,
282 D3D12_HEAP_FLAG_NONE,
284 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
286 IID_PPV_ARGS(buffer.resource.internalPointer()));
288 buffer.usage = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
291 allocateBuffer(buffer.uploadResource, size);
294 buffer.uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
295 buffer.uavDesc.Format = DXGI_FORMAT_UNKNOWN;
296 buffer.uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
297 buffer.uavDesc.Buffer.FirstElement = 0;
298 buffer.uavDesc.Buffer.NumElements =
static_cast<uint32_t
>(size) / stride;
299 buffer.uavDesc.Buffer.StructureByteStride = stride;
300 buffer.uavDesc.Buffer.CounterOffsetInBytes = 0;
303 buffer.srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
304 buffer.srvDesc.Format = DXGI_FORMAT_UNKNOWN;
305 buffer.srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
306 buffer.srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
307 buffer.srvDesc.Buffer.FirstElement = 0;
308 buffer.srvDesc.Buffer.NumElements =
static_cast<uint32_t
>(size) / stride;
309 buffer.srvDesc.Buffer.StructureByteStride = stride;
312 static const CD3DX12_RESOURCE_DESC bufferDesc2 = CD3DX12_RESOURCE_DESC::Buffer(4, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
314 device->CreateCommittedResource(
315 &defaultHeapProperties,
316 D3D12_HEAP_FLAG_NONE,
318 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
320 IID_PPV_ARGS(buffer.counterResource.internalPointer()));
325 allocateBuffer(buffer, buffer.size, data);
328 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(buffer.size);
330 device->CreateCommittedResource(
331 &readbackHeapProperties,
332 D3D12_HEAP_FLAG_NONE,
334 D3D12_RESOURCE_STATE_COPY_DEST,
336 IID_PPV_ARGS(buffer.resource.internalPointer()));
338 buffer.usage = D3D12_RESOURCE_STATE_COPY_DEST;
342 allocateBuffer(buffer, buffer.size, data);
344 buffer.vertexBufferView.BufferLocation = buffer.resource ? buffer.resource->GetGPUVirtualAddress() : buffer.pooledResource->mappedGpuRegion;
345 buffer.vertexBufferView.StrideInBytes = 0;
346 buffer.vertexBufferView.SizeInBytes =
static_cast<UINT
>(size);
349 BufferHandle handle = this->buffers.addResource(buffer);
356 releaseBufferInternal(bufferHandle);
366 return (
void*)(this->buffers[bufferHandle].resource);
374Cogs::BufferPool & Cogs::BuffersD3D12::getBufferPool(
const size_t size, uint32_t)
377 return bufferPool256;
378 }
else if (size <= 1024) {
379 return bufferPool1024;
381 assert(
false &&
"Buffer size too large.");
384 return *
reinterpret_cast<BufferPool *
>(0);
387void Cogs::BuffersD3D12::releaseBufferInternal(BufferHandle bufferHandle)
391 auto & buffer = buffers[bufferHandle];
393 recordBufferRelease(bufferHandle,
static_cast<BindFlags::EBindFlags>(buffer.bindFlags), buffer.size);
395 if (buffer.resource) {
396 graphicsDevice->context.currentFrameResources->orphanedResources.push_back(buffer.resource);
397 }
else if (buffer.pooledResource) {
398 graphicsDevice->context.currentFrameResources->orphanedBuffers.push_back(OrphanBufferD3D12{ buffer.pooledResource, buffer.pooledResource->pool });
401 buffers.removeResource(bufferHandle);
404void Cogs::BuffersD3D12::allocateBuffer(ResourceD3D12 & resource,
size_t size,
const void * data)
407 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size);
409 device->CreateCommittedResource(
410 &uploadHeapProperties,
411 D3D12_HEAP_FLAG_NONE,
413 D3D12_RESOURCE_STATE_GENERIC_READ,
415 IID_PPV_ARGS(resource.resource.internalPointer()));
417 resource.pooledResource = getBufferPool(size).allocate();
421 if (resource.pooledResource) {
422 memcpy(resource.pooledResource->mappedRegion, data, size);
424 UINT8 * resourceData;
425 resource.resource->Map(0,
nullptr,
reinterpret_cast<void**
>(&resourceData));
426 memcpy(resourceData, data, size);
427 resource.resource->Unmap(0,
nullptr);
Log implementation class.
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
const DXGI_FORMAT Formats[]
Must match up to Format definition.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains all Cogs related functionality.
@ Direct3D12
Graphics device using the Direct3D 12 API.
@ VertexData
Per vertex data.
@ InstanceMatrix
Instance matrix semantic.
@ Read
The buffer can be mapped and read from by the CPU after creation.
@ Write
The buffer can be mapped and written to by the CPU after creation.
@ None
The buffer can not be either read from or written to by the CPU after creation.
EBindFlags
Bind flags enumeration.
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
@ StructuredBufferWithCounter
The buffer can be bound as a structured buffer and read or written from shaders, with an additional a...
@ VertexBuffer
The buffer can be bound as input to the vertex shader stage as a vertex buffer.
@ RawBuffer
The buffer can be bound as a byte address buffer and read or written from shaders.
@ IndexBuffer
The buffer can be bound as input to the vertex shader stage as an index buffer.
@ None
The buffer will not be bound to the graphics pipeline. Suitable for staging resources.
@ StructuredBuffer
The buffer can be bound as a structured buffer and read or written from shaders.
void releaseVertexBuffer(VertexBufferHandle vertexBufferHandle)
Release the vertex buffer with the given handle.
BufferHandle loadBuffer(const void *data, const size_t size, Usage::EUsage usage, uint32_t accessMode, uint32_t bindFlags, uint32_t stride=0)
Loads a new buffer using the given data to populate the buffer.
void releaseInputLayout(InputLayoutHandle vertexFormatHandle)
Releases the input layout with the given inputLayoutHandle.
void retrieveSubBuffer(void *data, BufferHandle source, const size_t offset, const size_t size)
Retrieves the contents of a buffer.
void releaseResources()
Releases all allocated buffer resources.
void * getNativeHandle(BufferHandle bufferHandle) override
Get the device-specific handle (D3D buffer pointer, OpenGL buffer ID etc) associated with the given b...
void releaseIndexBuffer(IndexBufferHandle indexBufferHandle)
Releases the index buffer with the given handle.
IndexBufferHandle loadIndexBuffer(const void *vertexData, const size_t count, const size_t indexSize)
Loads a new index buffer and populates it with the given indexData.
VertexBufferHandle loadVertexBuffer(const void *vertexData, const size_t count, const VertexFormat &vertexFormat) override
Loads a new vertex buffer and populates it with the given data.
void releaseBuffer(BufferHandle bufferHandle)
Releases the buffer with the given bufferHandle.
InputLayoutHandle loadInputLayout(const VertexFormatHandle *vertexFormats, const size_t count, EffectHandle effectHandle)
Loads a new input layout to map vertex flow between vertex buffers with the given vertexFormats to ef...
static const Handle_t InvalidHandle
Represents an invalid handle.
Vertex element structure used to describe a single data element in a vertex for the input assembler.
InputType inputType
Input type of the element, vertex or instance data.
DataFormat format
Format of the element.
uint16_t offset
Offset in bytes from the vertex position in memory.
uint16_t semanticIndex
Index for the semantic mapping.
ElementSemantic semantic
Semantic mapping of the element (position, normal, etc...).
uint16_t instanceStep
Instance step factor.