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);
111 return buffers.addResource(buffer);
116 return loadVertexBuffer(vertexData, count, *VertexFormats::getVertexFormat(vertexFormatHandle));
121 releaseBufferInternal(vertexBufferHandle);
128 const size_t size = count * indexSize;
130 allocateBuffer(buffer, size, indexData);
132 buffer.indexBufferView.BufferLocation = buffer.resource ? buffer.resource->GetGPUVirtualAddress() : buffer.pooledResource->mappedGpuRegion;
133 buffer.indexBufferView.SizeInBytes =
static_cast<UINT
>(size);
134 buffer.indexBufferView.Format = indexSize ==
sizeof(UINT) ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT;
135 buffer.count = count;
138 return buffers.addResource(buffer);
143 releaseBufferInternal(indexBufferHandle);
150 auto & inputElements = inputLayout.inputElements;
151 auto & inputElementCount = inputLayout.inputElementCount;
153 for (
size_t i = 0; i < count; ++i) {
154 const VertexFormat & vertexFormat = *VertexFormats::getVertexFormat(vertexFormats[i]);
155 const size_t numElements = vertexFormat.
elements.size();
157 for (
size_t j = 0; j < numElements; ++j) {
160 if (inputElementCount >= D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT) {
161 LOG_ERROR(logger,
"Input element count exceeds limit set by D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT.");
168 assert(format != DXGI_FORMAT_UNKNOWN &&
"Unknown data format. Check input vertex formats.");
171 D3D12_INPUT_ELEMENT_DESC elementDescription = {
172 Direct3D12::Semantics[(int)element.
semantic],
175 static_cast<UINT
>(i),
176 static_cast<UINT
>(element.
offset),
177 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
181 inputElements[inputElementCount++] = elementDescription;
184 for (uint32_t m = 0; m < 4; ++m) {
185 D3D12_INPUT_ELEMENT_DESC elementDescription = {
186 Direct3D12::Semantics[(int)element.
semantic],
188 DXGI_FORMAT_R32G32B32A32_FLOAT,
189 static_cast<UINT
>(i),
190 static_cast<UINT
>(element.
offset + m * 4 *
sizeof(float)),
191 D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA,
195 inputElements[inputElementCount++] = elementDescription;
198 D3D12_INPUT_ELEMENT_DESC elementDescription = {
199 Direct3D12::Semantics[(int)element.
semantic],
202 static_cast<UINT
>(i),
203 static_cast<UINT
>(element.
offset),
204 D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA,
208 inputElements[inputElementCount++] = elementDescription;
214 return inputLayouts.addResource(inputLayout);
219 inputLayouts.removeResource(inputLayoutHandle);
225 buffer.bindFlags = bindFlags;
229 allocateBuffer(buffer, size, data);
231 if (buffer.pooledResource) {
232 buffer.cbvDesc.BufferLocation = buffer.pooledResource->mappedGpuRegion;
234 buffer.cbvDesc.BufferLocation = buffer.resource->GetGPUVirtualAddress();
236 buffer.cbvDesc.SizeInBytes =
static_cast<UINT
>(size);
237 buffer.cbvDesc.SizeInBytes = (buffer.cbvDesc.SizeInBytes + 255) & ~255;
240 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
242 device->CreateCommittedResource(
243 &defaultHeapProperties,
244 D3D12_HEAP_FLAG_NONE,
246 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
248 IID_PPV_ARGS(buffer.resource.internalPointer()));
250 buffer.usage = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
253 allocateBuffer(buffer.uploadResource, size, data);
256 buffer.uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
257 buffer.uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
258 buffer.uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
259 buffer.uavDesc.Buffer.FirstElement = 0;
260 buffer.uavDesc.Buffer.NumElements =
static_cast<uint32_t
>(size) / 4;
261 buffer.uavDesc.Buffer.StructureByteStride = 0;
262 buffer.uavDesc.Buffer.CounterOffsetInBytes = 0;
265 buffer.srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
266 buffer.srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
267 buffer.srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
268 buffer.srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
269 buffer.srvDesc.Buffer.FirstElement = 0;
270 buffer.srvDesc.Buffer.NumElements =
static_cast<uint32_t
>(size) / 4;
271 buffer.srvDesc.Buffer.StructureByteStride = 0;
274 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
276 device->CreateCommittedResource(
277 &defaultHeapProperties,
278 D3D12_HEAP_FLAG_NONE,
280 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
282 IID_PPV_ARGS(buffer.resource.internalPointer()));
284 buffer.usage = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
287 allocateBuffer(buffer.uploadResource, size);
290 buffer.uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
291 buffer.uavDesc.Format = DXGI_FORMAT_UNKNOWN;
292 buffer.uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
293 buffer.uavDesc.Buffer.FirstElement = 0;
294 buffer.uavDesc.Buffer.NumElements =
static_cast<uint32_t
>(size) / stride;
295 buffer.uavDesc.Buffer.StructureByteStride = stride;
296 buffer.uavDesc.Buffer.CounterOffsetInBytes = 0;
299 buffer.srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
300 buffer.srvDesc.Format = DXGI_FORMAT_UNKNOWN;
301 buffer.srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
302 buffer.srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
303 buffer.srvDesc.Buffer.FirstElement = 0;
304 buffer.srvDesc.Buffer.NumElements =
static_cast<uint32_t
>(size) / stride;
305 buffer.srvDesc.Buffer.StructureByteStride = stride;
308 static const CD3DX12_RESOURCE_DESC bufferDesc2 = CD3DX12_RESOURCE_DESC::Buffer(4, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
310 device->CreateCommittedResource(
311 &defaultHeapProperties,
312 D3D12_HEAP_FLAG_NONE,
314 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
316 IID_PPV_ARGS(buffer.counterResource.internalPointer()));
321 allocateBuffer(buffer, buffer.size, data);
324 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(buffer.size);
326 device->CreateCommittedResource(
327 &readbackHeapProperties,
328 D3D12_HEAP_FLAG_NONE,
330 D3D12_RESOURCE_STATE_COPY_DEST,
332 IID_PPV_ARGS(buffer.resource.internalPointer()));
334 buffer.usage = D3D12_RESOURCE_STATE_COPY_DEST;
338 allocateBuffer(buffer, buffer.size, data);
340 buffer.vertexBufferView.BufferLocation = buffer.resource ? buffer.resource->GetGPUVirtualAddress() : buffer.pooledResource->mappedGpuRegion;
341 buffer.vertexBufferView.StrideInBytes = 0;
342 buffer.vertexBufferView.SizeInBytes =
static_cast<UINT
>(size);
345 return this->buffers.addResource(buffer);
350 releaseBufferInternal(bufferHandle);
360 return (
void*)(this->buffers[bufferHandle].resource);
368Cogs::BufferPool & Cogs::BuffersD3D12::getBufferPool(
const size_t size, uint32_t)
371 return bufferPool256;
372 }
else if (size <= 1024) {
373 return bufferPool1024;
375 assert(
false &&
"Buffer size too large.");
378 return *
reinterpret_cast<BufferPool *
>(0);
381void Cogs::BuffersD3D12::releaseBufferInternal(BufferHandle bufferHandle)
383 auto & buffer = buffers[bufferHandle];
385 if (buffer.resource) {
386 graphicsDevice->context.currentFrameResources->orphanedResources.push_back(buffer.resource);
387 }
else if (buffer.pooledResource) {
388 graphicsDevice->context.currentFrameResources->orphanedBuffers.push_back(OrphanBufferD3D12{ buffer.pooledResource, buffer.pooledResource->pool });
391 buffers.removeResource(bufferHandle);
394void Cogs::BuffersD3D12::allocateBuffer(ResourceD3D12 & resource,
size_t size,
const void * data)
397 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size);
399 device->CreateCommittedResource(
400 &uploadHeapProperties,
401 D3D12_HEAP_FLAG_NONE,
403 D3D12_RESOURCE_STATE_GENERIC_READ,
405 IID_PPV_ARGS(resource.resource.internalPointer()));
407 resource.pooledResource = getBufferPool(size).allocate();
411 if (resource.pooledResource) {
412 memcpy(resource.pooledResource->mappedRegion, data, size);
414 UINT8 * resourceData;
415 resource.resource->Map(0,
nullptr,
reinterpret_cast<void**
>(&resourceData));
416 memcpy(resourceData, data, size);
417 resource.resource->Unmap(0,
nullptr);
Log implementation class.
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.
@ 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.