Cogs.Core
BuffersD3D11.cpp
1#include "BuffersD3D11.h"
2#include "FormatsD3D11.h"
3#include "GraphicsDeviceD3D11.h"
4
5#include "Foundation/Logging/Logger.h"
6
7#include <OsoMemoryProfiler/CogsMemoryProfile.h>
8
9#include <sstream>
10
11namespace
12{
13 Cogs::Logging::Log logger = Cogs::Logging::getLogger("BuffersD3D11");
14
15}
16
17namespace Cogs
18{
19 namespace Direct3D11
20 {
21 const DXGI_FORMAT IndexFormats[] = {
22 DXGI_FORMAT_R16_UINT,
23 DXGI_FORMAT_R32_UINT
24 };
25
26 LPCSTR Semantics[] = {
27 "POSITION",
28 "NORMAL",
29 "COLOR",
30 "TEXCOORD",
31 "TANGENT",
32 "INSTANCEVECTOR",
33 "INSTANCEMATRIX",
34 };
35 }
36
37#ifdef COGSRENDERING_GFX_ANNOTATE
38 void doAnnotate(Cogs::BufferD3D11& buffer, const StringView& name, const int64_t /*id*/)
39 {
40 if (name.empty()) {
41 return;
42 }
43
44 if (buffer.buffer) {
45 buffer.buffer->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast<UINT>(name.length()), name.data());
46 }
47 if (buffer.uav) {
48 const std::string m = std::string(name) + "_UAV";
49 buffer.uav->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast<UINT>(m.length()), m.c_str());
50 }
51 if (buffer.srv) {
52 const std::string m = std::string(name) + "_SRV";
53 buffer.srv->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast<UINT>(m.length()), m.c_str());
54 }
55 }
56#endif
57
58}
59
60Cogs::BuffersD3D11::BuffersD3D11(GraphicsDeviceD3D11 * device) :
61 buffers(256, 256, device->getResourceAllocator()),
62 inputLayouts(256, 256, device->getResourceAllocator())
63{
64
65}
66
68{
69#if defined( OSOMP_EnableProfiler )
70 OsoMPAttribute attribute = { COGSMEM_NameAttribute, ATTRIBUTETYPE_String };
71
72 std::string nameStr(name);
73 attribute.mData.mText = nameStr.c_str();
74 RegisterGPUResourceAttributes(buffers[handle].buffer, &attribute, 1);
75#endif
76
77#ifdef COGSRENDERING_GFX_ANNOTATE
78 doAnnotate(buffers[handle], name, handle.handle);
79#endif
80
81#if !defined(OSOMP_EnableProfiler) && !defined(COGSRENDERING_GFX_ANNOTATE)
82 (void)handle;
83 (void)name;
84#endif
85
86}
87
89{
90#if defined( OSOMP_EnableProfiler )
91 OsoMPAttribute attribute = { COGSMEM_NameAttribute, ATTRIBUTETYPE_String };
92
93 attribute.mData.mText = std::string(name).c_str();
94 RegisterGPUResourceAttributes(buffers[handle].buffer, &attribute, 1);
95#endif
96
97#ifdef COGSRENDERING_GFX_ANNOTATE
98 doAnnotate(buffers[handle], name, handle.handle);
99#endif
100
101#if !defined(OSOMP_EnableProfiler) && !defined(COGSRENDERING_GFX_ANNOTATE)
102 (void)handle;
103 (void)name;
104#endif
105}
106
107Cogs::VertexBufferHandle Cogs::BuffersD3D11::loadVertexBuffer(const void * vertexData, const size_t count, const VertexFormat & vertexFormat)
108{
109 const uint32_t stride = getSize(vertexFormat);
110 const size_t size = count * stride;
111
112 auto handle = loadBuffer(vertexData, size, Usage::Dynamic, AccessMode::Write, BindFlags::VertexBuffer);
113 auto & buffer = buffers[handle];
114
115 auto formatHandle = createVertexFormat(vertexFormat.elements.data(), vertexFormat.elements.size());
116
117 buffer.vertexBuffer.vertexFormat = getVertexFormat(formatHandle);
118
119 return handle;
120}
121
122Cogs::VertexBufferHandle Cogs::BuffersD3D11::loadVertexBuffer(const void * vertexData, const size_t count, VertexFormatHandle vertexFormatHandle)
123{
124 return loadVertexBuffer(vertexData, count, *VertexFormats::getVertexFormat(vertexFormatHandle));
125}
126
128{
129 buffers.removeResource(vertexBufferHandle);
130}
131
132Cogs::IndexBufferHandle Cogs::BuffersD3D11::loadIndexBuffer(const void * indexData, const size_t count, const size_t indexSize)
133{
134 const size_t size = count * indexSize;
135
136 auto handle = loadBuffer(indexData, size, Usage::Dynamic, AccessMode::Write, BindFlags::IndexBuffer);
137 auto & buffer = buffers[handle];
138
139 buffer.indexBuffer.count = static_cast<uint32_t>(count);
140 buffer.indexBuffer.indexFormat = Direct3D11::IndexFormats[indexSize == 2 ? 0 : 1];
141
142 return handle;
143}
144
146{
147 buffers.removeResource(indexBufferHandle);
148}
149
151{
152 if (!HandleIsValid(effectHandle)) {
153 LOG_ERROR(logger, "Cannot create input layout for invalid effect.");
155 }
156
157 InputLayoutD3D11 inputLayout;
158
159 inputLayout.numFormats = count;
160 for (size_t i = 0; i < count; ++i) {
161 inputLayout.formats[i] = getVertexFormat(vertexFormats[i]);
162 }
163
164 if (effectHandle) {
165 D3D11_INPUT_ELEMENT_DESC inputElements[kMaxVertexInputSlots] = {};
166 UINT inputElementCount = 0;
167
168 for (size_t i = 0; i < count; ++i) {
169 const VertexFormat& vertexFormat = *VertexFormats::getVertexFormat(vertexFormats[i]);
170 const size_t numElements = vertexFormat.elements.size();
171
172 for (size_t j = 0; j < numElements; ++j) {
173 const VertexElement& element = vertexFormat.elements[j];
174
175 DXGI_FORMAT format = Direct3D11::Formats[(int)element.format];
176 if (format == DXGI_FORMAT_UNKNOWN) {
177
178 // Silently promote 8 and 16 bit 3-channel formats to 4-channel formats since
179 // these formats doesn't exist for DXGI and this promotion should be invisible
180 // if the shader specify 3-channel input.
181 switch (element.format) {
182 case Format::R8G8B8_SINT: format = DXGI_FORMAT_R8G8B8A8_SINT; break;
183 case Format::R8G8B8_UINT: format = DXGI_FORMAT_R8G8B8A8_UINT; break;
184 case Format::R8G8B8_SNORM: format = DXGI_FORMAT_R8G8B8A8_SNORM; break;
185 case Format::R8G8B8_UNORM: format = DXGI_FORMAT_R8G8B8A8_UNORM; break;
186 case Format::R16G16B16_SINT: format = DXGI_FORMAT_R16G16B16A16_SINT; break;
187 case Format::R16G16B16_UINT: format = DXGI_FORMAT_R16G16B16A16_UINT; break;
188 case Format::R16G16B16_SNORM: format = DXGI_FORMAT_R16G16B16A16_SNORM; break;
189 case Format::R16G16B16_UNORM: format = DXGI_FORMAT_R16G16B16A16_UNORM; break;
190 default:
191 LOG_ERROR(logger, "Unsupported data format %d", int(element.format));
193 }
194 }
195 assert(format != DXGI_FORMAT_UNKNOWN);
196
197 if (element.inputType == InputType::VertexData) {
198 D3D11_INPUT_ELEMENT_DESC elementDescription = {
199 Direct3D11::Semantics[(int)element.semantic],
200 element.semanticIndex,
201 format,
202 static_cast<UINT>(i),
203 static_cast<UINT>(element.offset),
204 D3D11_INPUT_PER_VERTEX_DATA,
205 0
206 };
207
208 inputElements[inputElementCount++] = elementDescription;
209 }
210 else {
212 for (uint32_t m = 0; m < 4; ++m) {
213 D3D11_INPUT_ELEMENT_DESC elementDescription = {
214 Direct3D11::Semantics[(int)element.semantic],
215 element.semanticIndex * 4 + m,
216 format,
217 static_cast<UINT>(i),
218 static_cast<UINT>(element.offset + m * 4 * sizeof(float)),
219 D3D11_INPUT_PER_INSTANCE_DATA,
220 element.instanceStep
221 };
222
223 inputElements[inputElementCount++] = elementDescription;
224 }
225 }
226 else {
227 D3D11_INPUT_ELEMENT_DESC elementDescription = {
228 Direct3D11::Semantics[(int)element.semantic],
229 element.semanticIndex,
230 format,
231 static_cast<UINT>(i),
232 static_cast<UINT>(element.offset),
233 D3D11_INPUT_PER_INSTANCE_DATA,
234 element.instanceStep
235 };
236
237 inputElements[inputElementCount++] = elementDescription;
238 }
239 }
240 if (inputElementCount > D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT) {
241 LOG_ERROR(logger, "Input element count exceeds limit set by D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT.");
243 }
244 }
245 }
246
247 auto & effect = effects->effects[effectHandle];
248
249 auto & vertexShader = effect.vertexShader;
250 auto byteCode = static_cast<ID3DBlob *>(&*vertexShader.byteCode);
251
252 auto hr = device->CreateInputLayout(inputElements,
253 inputElementCount,
254 byteCode->GetBufferPointer(),
255 byteCode->GetBufferSize(),
256 inputLayout.resource.internalPointer());
257
258 if (FAILED(hr)) {
259 LOG_ERROR(logger, "CreateInputLayout returned: %s.", direct3D11ReturnCodeAsString(hr));
261 }
262 }
263
264 return inputLayouts.addResource(std::move(inputLayout));
265}
266
268{
269 inputLayouts.removeResource(inputLayoutHandle);
270}
271
272namespace Cogs
273{
274 namespace Direct3D11
275 {
276 D3D11_USAGE Usage[] = {
277 D3D11_USAGE_DEFAULT,
278 D3D11_USAGE_IMMUTABLE,
279 D3D11_USAGE_DYNAMIC,
280 D3D11_USAGE_STAGING,
281 };
282
283 UINT getBindFlags(uint32_t bindFlags)
284 {
285 UINT d3dBindFlags = 0;
286
287 d3dBindFlags |= bindFlags & Cogs::BindFlags::VertexBuffer ? D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER : 0;
288 d3dBindFlags |= bindFlags & Cogs::BindFlags::IndexBuffer ? D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER : 0;
289 d3dBindFlags |= bindFlags & Cogs::BindFlags::ConstantBuffer ? D3D11_BIND_CONSTANT_BUFFER : 0;
290 d3dBindFlags |= bindFlags & Cogs::BindFlags::RawBuffer ? D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE : 0;
291 d3dBindFlags |= bindFlags & Cogs::BindFlags::StructuredBuffer ? D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE : 0;
292 d3dBindFlags |= bindFlags & Cogs::BindFlags::StructuredBufferWithCounter ? D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE : 0;
293
294 return d3dBindFlags;
295 }
296 }
297}
298
299namespace {
300
301
302 void loadBufferLogError(const char* what, HRESULT hr, const void * data, const size_t size, Cogs::Usage::EUsage usage, uint32_t accessMode, uint32_t bindFlags, uint32_t stride)
303 {
304 LOG_ERROR(logger, "%s (data=%p, size=%zu, stride=%u, usage=%s, accessMode=%s, bindFlags=%s): %s",
305 what,
306 data,
307 size,
308 stride,
309 Cogs::getUsageString(usage),
310 Cogs::getAccessModeString(accessMode),
311 Cogs::getBindFlagsString(bindFlags),
312 Cogs::direct3D11ReturnCodeAsString(hr));
313 }
314
315
316}
317
318Cogs::BufferHandle Cogs::BuffersD3D11::loadBuffer(const void * data, const size_t size, Usage::EUsage usage, uint32_t accessMode, uint32_t bindFlags, uint32_t stride)
319{
320 D3D11_BUFFER_DESC bufferDescription = {};
321 bufferDescription.Usage = Direct3D11::Usage[usage];
322
323 if (bindFlags & BindFlags::ConstantBuffer) {
324 bufferDescription.ByteWidth = static_cast<UINT>(16 * ((size + 15) / 16)); // Constant buffers size must be a multiple of 16
325 //assert(bufferDescription.ByteWidth <= (D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * sizeof(float) * 4));
326 } else {
327 bufferDescription.ByteWidth = static_cast<UINT>(size);
328 }
329
330 const bool isStructured = (bindFlags & BindFlags::StructuredBuffer) || (bindFlags & BindFlags::StructuredBufferWithCounter);
331 const bool isRaw = (bindFlags & BindFlags::RawBuffer) != 0;
332
333 bufferDescription.BindFlags = Direct3D11::getBindFlags(bindFlags);
334 bufferDescription.CPUAccessFlags = ((accessMode & AccessMode::Write) ? D3D11_CPU_ACCESS_WRITE : 0) | ((accessMode & AccessMode::Read) ? D3D11_CPU_ACCESS_READ : 0);
335
336 if (isStructured) {
337 bufferDescription.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
338 bufferDescription.StructureByteStride = stride;
339 } else if (isRaw) {
340 bufferDescription.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
341 }
342
343 BufferD3D11 buffer = {};
344 buffer.size = size;
345 assert(uint32_t(bindFlags) < std::numeric_limits<uint16_t>::max() && "Bind flags out of range.");
346 buffer.bindFlags = static_cast<uint16_t>(bindFlags);
347
348 HRESULT hr;
349
350 if (data) {
351 D3D11_SUBRESOURCE_DATA initData = {};
352 initData.pSysMem = data;
353
354 hr = device->CreateBuffer(&bufferDescription, &initData, buffer.buffer.internalPointer());
355 if(context->uploadStatisticsEnabled) context->uploadStatisticsBufferUpload(size);
356 } else {
357 hr = device->CreateBuffer(&bufferDescription, nullptr, buffer.buffer.internalPointer());
358 }
359
360 if (bindFlags & BindFlags::VertexBuffer) {
361 RegisterGPUResource(buffer.buffer, bufferDescription.ByteWidth, MemBlockType::GPUVertexBuffer);
362 }
363 else if (bindFlags & BindFlags::IndexBuffer) {
364 RegisterGPUResource(buffer.buffer, bufferDescription.ByteWidth, MemBlockType::GPUIndexBuffer);
365 }
366 else if (bindFlags & BindFlags::ConstantBuffer) {
367 RegisterGPUResource(buffer.buffer, bufferDescription.ByteWidth, MemBlockType::GPUConstantBuffer);
368 }
369 else {
370 RegisterGPUResource(buffer.buffer, bufferDescription.ByteWidth, MemBlockType::GPUBuffer);
371 }
372
373 if (FAILED(hr)) {
374 loadBufferLogError("Failed to create buffer", hr, data, size, usage, accessMode, bindFlags, stride);
376 }
377
378 if (isStructured || isRaw) {
379 const uint32_t numElements = static_cast<uint32_t>(size) / stride;
380
381 buffer.structuredBuffer.count = numElements;
382
383 D3D11_UNORDERED_ACCESS_VIEW_DESC uavDescription = {};
384 uavDescription.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
385 uavDescription.Format = isRaw ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_UNKNOWN;
386 uavDescription.Buffer.Flags = (bindFlags & BindFlags::StructuredBufferWithCounter) ? D3D11_BUFFER_UAV_FLAG_COUNTER : (isRaw ? D3D11_BUFFER_UAV_FLAG_RAW : 0);
387 uavDescription.Buffer.FirstElement = 0;
388 uavDescription.Buffer.NumElements = numElements;
389
390 hr = device->CreateUnorderedAccessView(buffer.buffer, &uavDescription, buffer.uav.internalPointer());
391
392 if (FAILED(hr)) {
393 loadBufferLogError("Failed to create structured buffer UAV", hr, data, size, usage, accessMode, bindFlags, stride);
395 }
396
397 D3D11_SHADER_RESOURCE_VIEW_DESC srvDescription = {};
398 srvDescription.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
399 srvDescription.Format = isRaw ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_UNKNOWN;
400 srvDescription.BufferEx.Flags = isRaw ? D3D11_BUFFEREX_SRV_FLAG_RAW : 0;
401 srvDescription.BufferEx.FirstElement = 0;
402 srvDescription.BufferEx.NumElements = numElements;
403
404 hr = device->CreateShaderResourceView(buffer.buffer, &srvDescription, buffer.srv.internalPointer());
405 if (FAILED(hr)) {
406 loadBufferLogError("Failed to create buffer shader resource view", hr, data, size, usage, accessMode, bindFlags, stride);
408 }
409 }
410
411 bufferMemoryConsumption += buffer.size;
412
413 return buffers.addResource(std::move(buffer));
414}
415
417{
418 if (!bufferHandle) return;
419
420 BufferD3D11& buffer = buffers[bufferHandle];
421 bufferMemoryConsumption -= buffer.size;
422
423 buffers.removeResource(bufferHandle);
424}
425
427{
428 return (void*)(this->buffers[bufferHandle].buffer);
429}
430
432{
433 //TODO: Reimplement once pinning is properly in place.
434 //buffers.clear();
435}
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
Definition: StringView.h:171
constexpr size_t length() const noexcept
Get the length of the string.
Definition: StringView.h:185
constexpr bool empty() const noexcept
Check if the string is empty.
Definition: StringView.h:122
const DXGI_FORMAT Formats[]
Must match up to Format definition.
Definition: FormatsD3D11.cpp:6
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
@ Direct3D11
Graphics device using the Direct3D 11 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
@ 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
@ StructuredBuffer
The buffer can be bound as a structured buffer and read or written from shaders.
Definition: Flags.h:80
void releaseInputLayout(InputLayoutHandle vertexFormatHandle)
Releases the input layout with the given inputLayoutHandle.
void annotate(BufferHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
void * getNativeHandle(BufferHandle bufferHandle) override
Get the device-specific handle (D3D buffer pointer, OpenGL buffer ID etc) associated with the given b...
void releaseBuffer(BufferHandle bufferHandle)
Releases the buffer with the given bufferHandle.
void releaseVertexBuffer(VertexBufferHandle vertexBufferHandle)
Release the vertex buffer with the given handle.
VertexBufferHandle loadVertexBuffer(const void *vertexData, const size_t count, const VertexFormat &vertexFormat)
Loads a new vertex buffer and populates it with the given data.
InputLayoutHandle loadInputLayout(const VertexFormatHandle *vertexFormats, const size_t count, EffectHandle effectHandle) override
Loads a new input layout to map vertex flow between vertex buffers with the given vertexFormats to ef...
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.
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.
void releaseResources()
Releases all allocated buffer resources.
void releaseIndexBuffer(IndexBufferHandle indexBufferHandle)
Releases the index buffer with the given handle.
handle_type handle
Internal resource handle.
Definition: Common.h:74
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:80
Usage flags for buffers.
Definition: Flags.h:21
EUsage
Usage enumeration.
Definition: Flags.h:24
@ Dynamic
Buffer will be loaded and modified with some frequency.
Definition: Flags.h:30
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