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 return buffers.addResource(buffer);
112}
113
114Cogs::VertexBufferHandle Cogs::BuffersD3D12::loadVertexBuffer(const void * vertexData, const size_t count, VertexFormatHandle vertexFormatHandle)
115{
116 return loadVertexBuffer(vertexData, count, *VertexFormats::getVertexFormat(vertexFormatHandle));
117}
118
120{
121 releaseBufferInternal(vertexBufferHandle);
122}
123
124Cogs::IndexBufferHandle Cogs::BuffersD3D12::loadIndexBuffer(const void * indexData, const size_t count, const size_t indexSize)
125{
126 BufferD3D12 buffer;
127
128 const size_t size = count * indexSize;
129
130 allocateBuffer(buffer, size, indexData);
131
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;
136 buffer.bindFlags = BindFlags::IndexBuffer;
137
138 return buffers.addResource(buffer);
139}
140
142{
143 releaseBufferInternal(indexBufferHandle);
144}
145
146Cogs::InputLayoutHandle Cogs::BuffersD3D12::loadInputLayout(const VertexFormatHandle * vertexFormats, const size_t count, EffectHandle /*effectHandle*/)
147{
148 InputLayoutD3D12 inputLayout;
149
150 auto & inputElements = inputLayout.inputElements;
151 auto & inputElementCount = inputLayout.inputElementCount;
152
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();
156
157 for (size_t j = 0; j < numElements; ++j) {
158 const VertexElement & element = vertexFormat.elements[j];
159
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.");
162
164 }
165
166 const DXGI_FORMAT format = Direct3D12::Formats[(int)element.format];
167
168 assert(format != DXGI_FORMAT_UNKNOWN && "Unknown data format. Check input vertex formats.");
169
170 if (element.inputType == InputType::VertexData) {
171 D3D12_INPUT_ELEMENT_DESC elementDescription = {
172 Direct3D12::Semantics[(int)element.semantic],
173 element.semanticIndex,
174 format,
175 static_cast<UINT>(i),
176 static_cast<UINT>(element.offset),
177 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
178 0
179 };
180
181 inputElements[inputElementCount++] = elementDescription;
182 } else {
184 for (uint32_t m = 0; m < 4; ++m) {
185 D3D12_INPUT_ELEMENT_DESC elementDescription = {
186 Direct3D12::Semantics[(int)element.semantic],
187 element.semanticIndex * 4 + m,
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,
192 element.instanceStep
193 };
194
195 inputElements[inputElementCount++] = elementDescription;
196 }
197 } else {
198 D3D12_INPUT_ELEMENT_DESC elementDescription = {
199 Direct3D12::Semantics[(int)element.semantic],
200 element.semanticIndex,
201 format,
202 static_cast<UINT>(i),
203 static_cast<UINT>(element.offset),
204 D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA,
205 element.instanceStep
206 };
207
208 inputElements[inputElementCount++] = elementDescription;
209 }
210 }
211 }
212 }
213
214 return inputLayouts.addResource(inputLayout);
215}
216
218{
219 inputLayouts.removeResource(inputLayoutHandle);
220}
221
222Cogs::BufferHandle Cogs::BuffersD3D12::loadBuffer(const void * data, const size_t size, Usage::EUsage usage, uint32_t accessMode, uint32_t bindFlags, uint32_t stride)
223{
224 BufferD3D12 buffer;
225 buffer.bindFlags = bindFlags;
226 buffer.size = size;
227
228 if ((bindFlags & BindFlags::ConstantBuffer) != 0) {
229 allocateBuffer(buffer, size, data);
230
231 if (buffer.pooledResource) {
232 buffer.cbvDesc.BufferLocation = buffer.pooledResource->mappedGpuRegion;
233 } else {
234 buffer.cbvDesc.BufferLocation = buffer.resource->GetGPUVirtualAddress();
235 }
236 buffer.cbvDesc.SizeInBytes = static_cast<UINT>(size);
237 buffer.cbvDesc.SizeInBytes = (buffer.cbvDesc.SizeInBytes + 255) & ~255; //NOTE: Alignment(?)
238 }
239 else if ((bindFlags & BindFlags::RawBuffer)) {
240 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
241
242 device->CreateCommittedResource(
243 &defaultHeapProperties,
244 D3D12_HEAP_FLAG_NONE,
245 &bufferDesc,
246 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
247 nullptr,
248 IID_PPV_ARGS(buffer.resource.internalPointer()));
249
250 buffer.usage = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
251
252 if (data) {
253 allocateBuffer(buffer.uploadResource, size, data);
254 }
255
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;
263
264 buffer.srvDesc = {};
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;
272 }
273 else if ((bindFlags & BindFlags::StructuredBuffer) || (bindFlags & BindFlags::StructuredBufferWithCounter)) {
274 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
275
276 device->CreateCommittedResource(
277 &defaultHeapProperties,
278 D3D12_HEAP_FLAG_NONE,
279 &bufferDesc,
280 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
281 nullptr,
282 IID_PPV_ARGS(buffer.resource.internalPointer()));
283
284 buffer.usage = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
285
286 if (data) {
287 allocateBuffer(buffer.uploadResource, size);
288 }
289
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;
297
298 buffer.srvDesc = {};
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;
306
307 if ((bindFlags & BindFlags::StructuredBufferWithCounter)) {
308 static const CD3DX12_RESOURCE_DESC bufferDesc2 = CD3DX12_RESOURCE_DESC::Buffer(4, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
309
310 device->CreateCommittedResource(
311 &defaultHeapProperties,
312 D3D12_HEAP_FLAG_NONE,
313 &bufferDesc2,
314 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
315 nullptr,
316 IID_PPV_ARGS(buffer.counterResource.internalPointer()));
317 }
318 }
319 else if (bindFlags == BindFlags::None) {
320 if (accessMode == AccessMode::Write || accessMode == AccessMode::None) {
321 allocateBuffer(buffer, buffer.size, data);
322 }
323 else if (accessMode == AccessMode::Read) {
324 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(buffer.size);
325
326 device->CreateCommittedResource(
327 &readbackHeapProperties,
328 D3D12_HEAP_FLAG_NONE,
329 &bufferDesc,
330 D3D12_RESOURCE_STATE_COPY_DEST,
331 nullptr,
332 IID_PPV_ARGS(buffer.resource.internalPointer()));
333
334 buffer.usage = D3D12_RESOURCE_STATE_COPY_DEST;
335 }
336 }
337 else {
338 allocateBuffer(buffer, buffer.size, data);
339
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);
343 }
344
345 return this->buffers.addResource(buffer);
346}
347
349{
350 releaseBufferInternal(bufferHandle);
351}
352
353void Cogs::BuffersD3D12::retrieveSubBuffer(void * data, BufferHandle source, const size_t offset, const size_t size)
354{
355
356}
357
359{
360 return (void*)(this->buffers[bufferHandle].resource);
361}
362
364{
365 buffers.clear();
366}
367
368Cogs::BufferPool & Cogs::BuffersD3D12::getBufferPool(const size_t size, uint32_t)
369{
370 if (size <= 256) {
371 return bufferPool256;
372 } else if (size <= 1024) {
373 return bufferPool1024;
374 } else {
375 assert(false && "Buffer size too large.");
376 }
377
378 return *reinterpret_cast<BufferPool *>(0);
379}
380
381void Cogs::BuffersD3D12::releaseBufferInternal(BufferHandle bufferHandle)
382{
383 auto & buffer = buffers[bufferHandle];
384
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 });
389 }
390
391 buffers.removeResource(bufferHandle);
392}
393
394void Cogs::BuffersD3D12::allocateBuffer(ResourceD3D12 & resource, size_t size, const void * data)
395{
396 if (size > 1024) {
397 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size);
398
399 device->CreateCommittedResource(
400 &uploadHeapProperties,
401 D3D12_HEAP_FLAG_NONE,
402 &bufferDesc,
403 D3D12_RESOURCE_STATE_GENERIC_READ,
404 nullptr,
405 IID_PPV_ARGS(resource.resource.internalPointer()));
406 } else {
407 resource.pooledResource = getBufferPool(size).allocate();
408 }
409
410 if (data) {
411 if (resource.pooledResource) {
412 memcpy(resource.pooledResource->mappedRegion, data, size);
413 } else {
414 UINT8 * resourceData;
415 resource.resource->Map(0, nullptr, reinterpret_cast<void**>(&resourceData));
416 memcpy(resourceData, data, size);
417 resource.resource->Unmap(0, nullptr);
418 }
419 }
420}
Log implementation class.
Definition: LogManager.h:139
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:180
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
@ 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:80
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