Cogs.Core
BuffersD3D12.cpp
1#include "BuffersD3D12.h"
2
3#include "Foundation/Logging/Logger.h"
4
5#include "EffectsD3D12.h"
6#include "FormatsD3D12.h"
7#include "GraphicsDeviceD3D12.h"
8
9namespace
10{
11 Cogs::Logging::Log logger = Cogs::Logging::getLogger("BuffersD3D12");
12}
13
14namespace Cogs
15{
16 namespace Direct3D12
17 {
18 const DXGI_FORMAT IndexFormats[] = {
19 DXGI_FORMAT_R16_UINT,
20 DXGI_FORMAT_R32_UINT
21 };
22
23 LPCSTR Semantics[] = {
24 "POSITION",
25 "NORMAL",
26 "COLOR",
27 "TEXCOORD",
28 "TANGENT",
29 "INSTANCEVECTOR",
30 "INSTANCEMATRIX",
31 };
32 }
33}
34
35Cogs::BufferPage::BufferPage(BufferContext & context, size_t pageSize)
36{
37 CD3DX12_HEAP_PROPERTIES heapProperties(context.heapType);
38 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(context.elementSize * pageSize);
39
40 auto hr = context.device->CreateCommittedResource(
41 &heapProperties,
42 D3D12_HEAP_FLAG_NONE,
43 &bufferDesc,
44 context.resourceState,
45 nullptr,
46 IID_PPV_ARGS(buffer.internalPointer()));
47
48 if (FAILED(hr)) {
49 return;
50 }
51
52 buffer->AddRef();
53
54 buffer->Map(0, nullptr, reinterpret_cast<void **>(&mappedRegion));
55 mappedGpuRegion = buffer->GetGPUVirtualAddress();
56
57 // Resize the backing store of the page to hold pageSize number of elements.
58 storage.resize(sizeof(PoolBuffer) * pageSize);
59
60 auto head = reinterpret_cast<PoolBuffer *>(storage.data());
61
62 // Initialize the linked list of elements chaining all elements in the page together.
63 for (size_t i = 0; i < pageSize; ++i) {
64 PoolBuffer * block = head + i;
65
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;
72
73 block->next = block + 1;
74 }
75
76 (head + pageSize - 1)->next = nullptr;
77}
78
79void Cogs::BuffersD3D12::initialize(struct GraphicsDeviceD3D12 * graphicsDevice)
80{
81 this->graphicsDevice = graphicsDevice;
82 this->device = graphicsDevice->device;
83 this->effects = &graphicsDevice->effects;
84
85 bufferPool256.initialize(device, 1024, 256, 128);
86 bufferPool1024.initialize(device, 1024, 1024, 128);
87}
88
89Cogs::VertexBufferHandle Cogs::BuffersD3D12::loadVertexBuffer(const void * vertexData, const size_t count, const VertexFormat & vertexFormat)
90{
91 BufferD3D12 buffer;
92
93 const size_t vertexSize = getSize(vertexFormat);
94 const size_t size = count * vertexSize;
95
96 allocateBuffer(buffer, size, vertexData);
97
98 buffer.size = size;
99 buffer.count = count;
100
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);
104
105 buffer.bindFlags = BindFlags::VertexBuffer;
106
107 auto formatHandle = createVertexFormat(vertexFormat.elements.data(), vertexFormat.elements.size());
108
109 buffer.vertexFormat = getVertexFormat(formatHandle);
110
111 BufferHandle handle = buffers.addResource(buffer);
112 recordBufferCreate(handle, BindFlags::VertexBuffer, size);
113 return handle;
114}
115
116Cogs::VertexBufferHandle Cogs::BuffersD3D12::loadVertexBuffer(const void * vertexData, const size_t count, VertexFormatHandle vertexFormatHandle)
117{
118 return loadVertexBuffer(vertexData, count, *VertexFormats::getVertexFormat(vertexFormatHandle));
119}
120
122{
123 releaseBufferInternal(vertexBufferHandle);
124}
125
126Cogs::IndexBufferHandle Cogs::BuffersD3D12::loadIndexBuffer(const void * indexData, const size_t count, const size_t indexSize)
127{
128 BufferD3D12 buffer;
129
130 const size_t size = count * indexSize;
131
132 allocateBuffer(buffer, size, indexData);
133
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;
138 buffer.bindFlags = BindFlags::IndexBuffer;
139
140 BufferHandle handle = buffers.addResource(buffer);
141 recordBufferCreate(handle, BindFlags::IndexBuffer, size);
142 return handle;
143}
144
146{
147 releaseBufferInternal(indexBufferHandle);
148}
149
150Cogs::InputLayoutHandle Cogs::BuffersD3D12::loadInputLayout(const VertexFormatHandle * vertexFormats, const size_t count, EffectHandle /*effectHandle*/)
151{
152 InputLayoutD3D12 inputLayout;
153
154 auto & inputElements = inputLayout.inputElements;
155 auto & inputElementCount = inputLayout.inputElementCount;
156
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();
160
161 for (size_t j = 0; j < numElements; ++j) {
162 const VertexElement & element = vertexFormat.elements[j];
163
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.");
166
168 }
169
170 const DXGI_FORMAT format = Direct3D12::Formats[(int)element.format];
171
172 assert(format != DXGI_FORMAT_UNKNOWN && "Unknown data format. Check input vertex formats.");
173
174 if (element.inputType == InputType::VertexData) {
175 D3D12_INPUT_ELEMENT_DESC elementDescription = {
176 Direct3D12::Semantics[(int)element.semantic],
177 element.semanticIndex,
178 format,
179 static_cast<UINT>(i),
180 static_cast<UINT>(element.offset),
181 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
182 0
183 };
184
185 inputElements[inputElementCount++] = elementDescription;
186 } else {
188 for (uint32_t m = 0; m < 4; ++m) {
189 D3D12_INPUT_ELEMENT_DESC elementDescription = {
190 Direct3D12::Semantics[(int)element.semantic],
191 element.semanticIndex * 4 + m,
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,
196 element.instanceStep
197 };
198
199 inputElements[inputElementCount++] = elementDescription;
200 }
201 } else {
202 D3D12_INPUT_ELEMENT_DESC elementDescription = {
203 Direct3D12::Semantics[(int)element.semantic],
204 element.semanticIndex,
205 format,
206 static_cast<UINT>(i),
207 static_cast<UINT>(element.offset),
208 D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA,
209 element.instanceStep
210 };
211
212 inputElements[inputElementCount++] = elementDescription;
213 }
214 }
215 }
216 }
217
218 return inputLayouts.addResource(inputLayout);
219}
220
222{
223 inputLayouts.removeResource(inputLayoutHandle);
224}
225
226Cogs::BufferHandle Cogs::BuffersD3D12::loadBuffer(const void * data, const size_t size, Usage::EUsage usage, uint32_t accessMode, uint32_t bindFlags, uint32_t stride)
227{
228 BufferD3D12 buffer;
229 buffer.bindFlags = bindFlags;
230 buffer.size = size;
231
232 if ((bindFlags & BindFlags::ConstantBuffer) != 0) {
233 allocateBuffer(buffer, size, data);
234
235 if (buffer.pooledResource) {
236 buffer.cbvDesc.BufferLocation = buffer.pooledResource->mappedGpuRegion;
237 } else {
238 buffer.cbvDesc.BufferLocation = buffer.resource->GetGPUVirtualAddress();
239 }
240 buffer.cbvDesc.SizeInBytes = static_cast<UINT>(size);
241 buffer.cbvDesc.SizeInBytes = (buffer.cbvDesc.SizeInBytes + 255) & ~255; //NOTE: Alignment(?)
242 }
243 else if ((bindFlags & BindFlags::RawBuffer)) {
244 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
245
246 device->CreateCommittedResource(
247 &defaultHeapProperties,
248 D3D12_HEAP_FLAG_NONE,
249 &bufferDesc,
250 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
251 nullptr,
252 IID_PPV_ARGS(buffer.resource.internalPointer()));
253
254 buffer.usage = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
255
256 if (data) {
257 allocateBuffer(buffer.uploadResource, size, data);
258 }
259
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;
267
268 buffer.srvDesc = {};
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;
276 }
277 else if ((bindFlags & BindFlags::StructuredBuffer) || (bindFlags & BindFlags::StructuredBufferWithCounter)) {
278 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
279
280 device->CreateCommittedResource(
281 &defaultHeapProperties,
282 D3D12_HEAP_FLAG_NONE,
283 &bufferDesc,
284 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
285 nullptr,
286 IID_PPV_ARGS(buffer.resource.internalPointer()));
287
288 buffer.usage = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
289
290 if (data) {
291 allocateBuffer(buffer.uploadResource, size);
292 }
293
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;
301
302 buffer.srvDesc = {};
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;
310
311 if ((bindFlags & BindFlags::StructuredBufferWithCounter)) {
312 static const CD3DX12_RESOURCE_DESC bufferDesc2 = CD3DX12_RESOURCE_DESC::Buffer(4, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
313
314 device->CreateCommittedResource(
315 &defaultHeapProperties,
316 D3D12_HEAP_FLAG_NONE,
317 &bufferDesc2,
318 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
319 nullptr,
320 IID_PPV_ARGS(buffer.counterResource.internalPointer()));
321 }
322 }
323 else if (bindFlags == BindFlags::None) {
324 if (accessMode == AccessMode::Write || accessMode == AccessMode::None) {
325 allocateBuffer(buffer, buffer.size, data);
326 }
327 else if (accessMode == AccessMode::Read) {
328 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(buffer.size);
329
330 device->CreateCommittedResource(
331 &readbackHeapProperties,
332 D3D12_HEAP_FLAG_NONE,
333 &bufferDesc,
334 D3D12_RESOURCE_STATE_COPY_DEST,
335 nullptr,
336 IID_PPV_ARGS(buffer.resource.internalPointer()));
337
338 buffer.usage = D3D12_RESOURCE_STATE_COPY_DEST;
339 }
340 }
341 else {
342 allocateBuffer(buffer, buffer.size, data);
343
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);
347 }
348
349 BufferHandle handle = this->buffers.addResource(buffer);
350 recordBufferCreate(handle, static_cast<BindFlags::EBindFlags>(bindFlags), size);
351 return handle;
352}
353
355{
356 releaseBufferInternal(bufferHandle);
357}
358
359void Cogs::BuffersD3D12::retrieveSubBuffer(void * data, BufferHandle source, const size_t offset, const size_t size)
360{
361
362}
363
365{
366 return (void*)(this->buffers[bufferHandle].resource);
367}
368
370{
371 buffers.clear();
372}
373
374Cogs::BufferPool & Cogs::BuffersD3D12::getBufferPool(const size_t size, uint32_t)
375{
376 if (size <= 256) {
377 return bufferPool256;
378 } else if (size <= 1024) {
379 return bufferPool1024;
380 } else {
381 assert(false && "Buffer size too large.");
382 }
383
384 return *reinterpret_cast<BufferPool *>(0);
385}
386
387void Cogs::BuffersD3D12::releaseBufferInternal(BufferHandle bufferHandle)
388{
389 if (!HandleIsValid(bufferHandle)) return;
390
391 auto & buffer = buffers[bufferHandle];
392
393 recordBufferRelease(bufferHandle, static_cast<BindFlags::EBindFlags>(buffer.bindFlags), buffer.size);
394
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 });
399 }
400
401 buffers.removeResource(bufferHandle);
402}
403
404void Cogs::BuffersD3D12::allocateBuffer(ResourceD3D12 & resource, size_t size, const void * data)
405{
406 if (size > 1024) {
407 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size);
408
409 device->CreateCommittedResource(
410 &uploadHeapProperties,
411 D3D12_HEAP_FLAG_NONE,
412 &bufferDesc,
413 D3D12_RESOURCE_STATE_GENERIC_READ,
414 nullptr,
415 IID_PPV_ARGS(resource.resource.internalPointer()));
416 } else {
417 resource.pooledResource = getBufferPool(size).allocate();
418 }
419
420 if (data) {
421 if (resource.pooledResource) {
422 memcpy(resource.pooledResource->mappedRegion, data, size);
423 } else {
424 UINT8 * resourceData;
425 resource.resource->Map(0, nullptr, reinterpret_cast<void**>(&resourceData));
426 memcpy(resourceData, data, size);
427 resource.resource->Unmap(0, nullptr);
428 }
429 }
430}
Log implementation class.
Definition: LogManager.h:140
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.
Definition: FormatsD3D12.cpp:9
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
@ 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.
Definition: Flags.h:48
@ Write
The buffer can be mapped and written to by the CPU after creation.
Definition: Flags.h:50
@ None
The buffer can not be either read from or written to by the CPU after creation.
Definition: Flags.h:46
EBindFlags
Bind flags enumeration.
Definition: Flags.h:64
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
Definition: Flags.h:72
@ StructuredBufferWithCounter
The buffer can be bound as a structured buffer and read or written from shaders, with an additional a...
Definition: Flags.h:82
@ VertexBuffer
The buffer can be bound as input to the vertex shader stage as a vertex buffer.
Definition: Flags.h:68
@ RawBuffer
The buffer can be bound as a byte address buffer and read or written from shaders.
Definition: Flags.h:78
@ IndexBuffer
The buffer can be bound as input to the vertex shader stage as an index buffer.
Definition: Flags.h:70
@ None
The buffer will not be bound to the graphics pipeline. Suitable for staging resources.
Definition: Flags.h:66
@ StructuredBuffer
The buffer can be bound as a structured buffer and read or written from shaders.
Definition: Flags.h:80
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.
Definition: Common.h:81
EUsage
Usage enumeration.
Definition: Flags.h:24
Vertex element structure used to describe a single data element in a vertex for the input assembler.
Definition: VertexFormat.h:38
InputType inputType
Input type of the element, vertex or instance data.
Definition: VertexFormat.h:43
DataFormat format
Format of the element.
Definition: VertexFormat.h:40
uint16_t offset
Offset in bytes from the vertex position in memory.
Definition: VertexFormat.h:39
uint16_t semanticIndex
Index for the semantic mapping.
Definition: VertexFormat.h:42
ElementSemantic semantic
Semantic mapping of the element (position, normal, etc...).
Definition: VertexFormat.h:41
uint16_t instanceStep
Instance step factor.
Definition: VertexFormat.h:44
Vertex format structure used to describe a single vertex for the input assembler.
Definition: VertexFormat.h:60
std::vector< VertexElement > elements
Vector containing all vertex elements of this format.
Definition: VertexFormat.h:62