1#include "BuffersD3D11.h"
2#include "FormatsD3D11.h"
3#include "GraphicsDeviceD3D11.h"
5#include "Foundation/Logging/Logger.h"
7#include <OsoMemoryProfiler/CogsMemoryProfile.h>
21 const DXGI_FORMAT IndexFormats[] = {
26 LPCSTR Semantics[] = {
37#ifdef COGSRENDERING_GFX_ANNOTATE
45 buffer.buffer->SetPrivateData(WKPDID_D3DDebugObjectName,
static_cast<UINT
>(name.
length()), name.
data());
48 const std::string m = std::string(name) +
"_UAV";
49 buffer.uav->SetPrivateData(WKPDID_D3DDebugObjectName,
static_cast<UINT
>(m.length()), m.c_str());
52 const std::string m = std::string(name) +
"_SRV";
53 buffer.srv->SetPrivateData(WKPDID_D3DDebugObjectName,
static_cast<UINT
>(m.length()), m.c_str());
60Cogs::BuffersD3D11::BuffersD3D11(GraphicsDeviceD3D11 * device) :
61 buffers(256, 256, device->getResourceAllocator()),
62 inputLayouts(256, 256, device->getResourceAllocator())
69#if defined( OSOMP_EnableProfiler )
70 OsoMPAttribute attribute = { COGSMEM_NameAttribute, ATTRIBUTETYPE_String };
72 std::string nameStr(name);
73 attribute.mData.mText = nameStr.c_str();
74 RegisterGPUResourceAttributes(buffers[handle].buffer, &attribute, 1);
77#ifdef COGSRENDERING_GFX_ANNOTATE
78 doAnnotate(buffers[handle], name, handle.
handle);
81#if !defined(OSOMP_EnableProfiler) && !defined(COGSRENDERING_GFX_ANNOTATE)
90#if defined( OSOMP_EnableProfiler )
91 OsoMPAttribute attribute = { COGSMEM_NameAttribute, ATTRIBUTETYPE_String };
93 attribute.mData.mText = std::string(name).c_str();
94 RegisterGPUResourceAttributes(buffers[handle].buffer, &attribute, 1);
97#ifdef COGSRENDERING_GFX_ANNOTATE
98 doAnnotate(buffers[handle], name, handle.
handle);
101#if !defined(OSOMP_EnableProfiler) && !defined(COGSRENDERING_GFX_ANNOTATE)
109 const uint32_t stride = getSize(vertexFormat);
110 const size_t size = count * stride;
113 auto & buffer = buffers[handle];
115 auto formatHandle = createVertexFormat(vertexFormat.
elements.data(), vertexFormat.
elements.size());
117 buffer.vertexBuffer.vertexFormat = getVertexFormat(formatHandle);
124 return loadVertexBuffer(vertexData, count, *VertexFormats::getVertexFormat(vertexFormatHandle));
129 buffers.removeResource(vertexBufferHandle);
134 const size_t size = count * indexSize;
137 auto & buffer = buffers[handle];
139 buffer.indexBuffer.count =
static_cast<uint32_t
>(count);
140 buffer.indexBuffer.indexFormat = Direct3D11::IndexFormats[indexSize == 2 ? 0 : 1];
147 buffers.removeResource(indexBufferHandle);
152 if (!HandleIsValid(effectHandle)) {
153 LOG_ERROR(logger,
"Cannot create input layout for invalid effect.");
159 inputLayout.numFormats = count;
160 for (
size_t i = 0; i < count; ++i) {
161 inputLayout.formats[i] = getVertexFormat(vertexFormats[i]);
165 D3D11_INPUT_ELEMENT_DESC inputElements[kMaxVertexInputSlots] = {};
166 UINT inputElementCount = 0;
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();
172 for (
size_t j = 0; j < numElements; ++j) {
176 if (format == DXGI_FORMAT_UNKNOWN) {
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;
191 LOG_ERROR(logger,
"Unsupported data format %d",
int(element.
format));
195 assert(format != DXGI_FORMAT_UNKNOWN);
198 D3D11_INPUT_ELEMENT_DESC elementDescription = {
199 Direct3D11::Semantics[(int)element.
semantic],
202 static_cast<UINT
>(i),
203 static_cast<UINT
>(element.
offset),
204 D3D11_INPUT_PER_VERTEX_DATA,
208 inputElements[inputElementCount++] = elementDescription;
212 for (uint32_t m = 0; m < 4; ++m) {
213 D3D11_INPUT_ELEMENT_DESC elementDescription = {
214 Direct3D11::Semantics[(int)element.
semantic],
217 static_cast<UINT
>(i),
218 static_cast<UINT
>(element.
offset + m * 4 *
sizeof(float)),
219 D3D11_INPUT_PER_INSTANCE_DATA,
223 inputElements[inputElementCount++] = elementDescription;
227 D3D11_INPUT_ELEMENT_DESC elementDescription = {
228 Direct3D11::Semantics[(int)element.
semantic],
231 static_cast<UINT
>(i),
232 static_cast<UINT
>(element.
offset),
233 D3D11_INPUT_PER_INSTANCE_DATA,
237 inputElements[inputElementCount++] = elementDescription;
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.");
247 auto & effect = effects->effects[effectHandle];
249 auto & vertexShader = effect.vertexShader;
250 auto byteCode =
static_cast<ID3DBlob *
>(&*vertexShader.byteCode);
252 auto hr = device->CreateInputLayout(inputElements,
254 byteCode->GetBufferPointer(),
255 byteCode->GetBufferSize(),
256 inputLayout.resource.internalPointer());
259 LOG_ERROR(logger,
"CreateInputLayout returned: %s.", direct3D11ReturnCodeAsString(hr));
264 return inputLayouts.addResource(std::move(inputLayout));
269 inputLayouts.removeResource(inputLayoutHandle);
276 D3D11_USAGE
Usage[] = {
278 D3D11_USAGE_IMMUTABLE,
283 UINT getBindFlags(uint32_t bindFlags)
285 UINT d3dBindFlags = 0;
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)
304 LOG_ERROR(logger,
"%s (data=%p, size=%zu, stride=%u, usage=%s, accessMode=%s, bindFlags=%s): %s",
309 Cogs::getUsageString(usage),
310 Cogs::getAccessModeString(accessMode),
311 Cogs::getBindFlagsString(bindFlags),
312 Cogs::direct3D11ReturnCodeAsString(hr));
320 D3D11_BUFFER_DESC bufferDescription = {};
321 bufferDescription.Usage = Direct3D11::Usage[usage];
324 bufferDescription.ByteWidth =
static_cast<UINT
>(16 * ((size + 15) / 16));
327 bufferDescription.ByteWidth =
static_cast<UINT
>(size);
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);
337 bufferDescription.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
338 bufferDescription.StructureByteStride = stride;
340 bufferDescription.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
345 assert(uint32_t(bindFlags) < std::numeric_limits<uint16_t>::max() &&
"Bind flags out of range.");
346 buffer.bindFlags =
static_cast<uint16_t
>(bindFlags);
351 D3D11_SUBRESOURCE_DATA initData = {};
352 initData.pSysMem = data;
354 hr = device->CreateBuffer(&bufferDescription, &initData, buffer.buffer.internalPointer());
355 if(context->uploadStatisticsEnabled) context->uploadStatisticsBufferUpload(size);
357 hr = device->CreateBuffer(&bufferDescription,
nullptr, buffer.buffer.internalPointer());
361 RegisterGPUResource(buffer.buffer, bufferDescription.ByteWidth, MemBlockType::GPUVertexBuffer);
364 RegisterGPUResource(buffer.buffer, bufferDescription.ByteWidth, MemBlockType::GPUIndexBuffer);
367 RegisterGPUResource(buffer.buffer, bufferDescription.ByteWidth, MemBlockType::GPUConstantBuffer);
370 RegisterGPUResource(buffer.buffer, bufferDescription.ByteWidth, MemBlockType::GPUBuffer);
374 loadBufferLogError(
"Failed to create buffer", hr, data, size, usage, accessMode, bindFlags, stride);
378 if (isStructured || isRaw) {
379 const uint32_t numElements =
static_cast<uint32_t
>(size) / stride;
381 buffer.structuredBuffer.count = numElements;
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;
387 uavDescription.Buffer.FirstElement = 0;
388 uavDescription.Buffer.NumElements = numElements;
390 hr = device->CreateUnorderedAccessView(buffer.buffer, &uavDescription, buffer.uav.internalPointer());
393 loadBufferLogError(
"Failed to create structured buffer UAV", hr, data, size, usage, accessMode, bindFlags, stride);
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;
404 hr = device->CreateShaderResourceView(buffer.buffer, &srvDescription, buffer.srv.internalPointer());
406 loadBufferLogError(
"Failed to create buffer shader resource view", hr, data, size, usage, accessMode, bindFlags, stride);
411 bufferMemoryConsumption += buffer.size;
413 return buffers.addResource(std::move(buffer));
418 if (!bufferHandle)
return;
421 bufferMemoryConsumption -= buffer.size;
423 buffers.removeResource(bufferHandle);
428 return (
void*)(this->buffers[bufferHandle].buffer);
Log implementation class.
Provides a weakly referenced view over the contents of a string.
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
constexpr size_t length() const noexcept
Get the length of the string.
constexpr bool empty() const noexcept
Check if the string is empty.
const DXGI_FORMAT Formats[]
Must match up to Format definition.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains all Cogs related functionality.
@ 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.
@ Write
The buffer can be mapped and 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.
@ StructuredBuffer
The buffer can be bound as a structured buffer and read or written from shaders.
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.
static const Handle_t InvalidHandle
Represents an invalid handle.
@ Dynamic
Buffer will be loaded and modified with some frequency.
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.