1#include "TexturesD3D11.h"
3#include "FormatsD3D11.h"
4#include "GraphicsDeviceD3D11.h"
6#include "Foundation/Logging/Logger.h"
8#include <OsoMemoryProfiler/CogsMemoryProfile.h>
17Cogs::TexturesD3D11::TexturesD3D11(GraphicsDeviceD3D11 * device) :
18 textures(256, 128, device->getResourceAllocator()),
19 samplerStates(128, 128, device->getResourceAllocator()),
20 graphicsDevice(device)
26#if defined(OSOMP_EnableProfiler) || defined(COGSRENDERING_GFX_ANNOTATE)
33#if defined( OSOMP_EnableProfiler )
34 OsoMPAttribute attribute = { COGSMEM_NameAttribute, ATTRIBUTETYPE_String };
36 std::string nameStr(name);
37 attribute.mData.mText = nameStr.c_str();
40 RegisterGPUResourceAttributes(textures[handle].texture2D.get<
void>(), &attribute, 1);
42 else if (t.texture3D) {
43 RegisterGPUResourceAttributes(textures[handle].texture3D.get<
void>(), &attribute, 1);
47#ifdef COGSRENDERING_GFX_ANNOTATE
48 if (name.
empty() || !handle) {
53 t.texture2D->SetPrivateData(WKPDID_D3DDebugObjectName,
static_cast<UINT
>(name.
length()), name.
data());
56 t.texture3D->SetPrivateData(WKPDID_D3DDebugObjectName,
static_cast<UINT
>(name.
length()), name.
data());
58 if (t.unorderedAccessView) {
59 const std::string m = std::string(name) +
"_UAV";
60 t.unorderedAccessView->SetPrivateData(WKPDID_D3DDebugObjectName,
static_cast<UINT
>(m.length()), m.c_str());
62 if (t.shaderResourceView) {
63 const std::string m = std::string(name) +
"_SRV";
64 t.shaderResourceView->SetPrivateData(WKPDID_D3DDebugObjectName,
static_cast<UINT
>(m.length()), m.c_str());
72 TextureD3D11 texture = { desc, desc.width, desc.height, desc.depth, desc.format,
nullptr,
nullptr,
nullptr };
74#if defined(OSOMP_EnableProfiler)
75 OsoMPAttribute profilerAttributes[7] = {
76 { COGSMEM_WidthAttribute, ATTRIBUTETYPE_Integer32,
static_cast<int32_t
>(desc.width) },
77 { COGSMEM_HeightAttribute, ATTRIBUTETYPE_Integer32,
static_cast<int32_t
>(desc.height) },
78 { COGSMEM_DepthAttribute, ATTRIBUTETYPE_Integer32,
static_cast<int32_t
>(desc.depth) },
79 { COGSMEM_LayersAttribute, ATTRIBUTETYPE_Integer32,
static_cast<int32_t
>(desc.layers) },
80 { COGSMEM_FacesAttribute, ATTRIBUTETYPE_Integer32,
static_cast<int32_t
>(desc.faces) },
81 { COGSMEM_LevelsAttribute, ATTRIBUTETYPE_Integer32,
static_cast<int32_t
>(desc.levels) },
82 { COGSMEM_FormatAttribute, ATTRIBUTETYPE_String },
85 profilerAttributes[6].mData.mText = getFormatInfo(desc.format)->
name;
88 const auto flags = desc.flags;
89 const auto format = desc.format;
90 const auto bytes = data ? data->offsets.data() : (
const void **)
nullptr;
96 if (desc.target == ResourceDimensions::Texture3D) {
97 texture.texture3D = (ID3D11Texture3D *)data->externalHandle;
100 texture.texture2D = (ID3D11Texture2D *)data->externalHandle;
106 const UINT mipLevels = generateMipmaps ? Cogs::getMipLevels(desc.width, desc.height) :
static_cast<UINT
>(desc.levels);
109 bindFlags |= D3D11_BIND_RENDER_TARGET;
113 bindFlags |= D3D11_BIND_DEPTH_STENCIL;
117 bindFlags |= D3D11_BIND_SHADER_RESOURCE;
121 bindFlags |= D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
124 D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
125 UINT CPUAccessFlag = 0;
126 if (flags & TextureFlags::UsageWriteStaging) {
128 usage = D3D11_USAGE_STAGING;
129 CPUAccessFlag = D3D11_CPU_ACCESS_WRITE;
133 usage = D3D11_USAGE_STAGING;
134 CPUAccessFlag = D3D11_CPU_ACCESS_READ;
137 if (desc.target == ResourceDimensions::Texture3D) {
138 D3D11_TEXTURE3D_DESC textureDesc = {};
139 textureDesc.Width = desc.width;
140 textureDesc.Height = desc.height;
141 textureDesc.Depth = desc.depth;
142 textureDesc.MipLevels = mipLevels;
143 textureDesc.Format = formatD3D;
144 textureDesc.Usage = usage;
145 textureDesc.BindFlags = bindFlags;
146 textureDesc.CPUAccessFlags = CPUAccessFlag;
150 if (FAILED(hr = graphicsDevice->getDevice()->CreateTexture3D(&textureDesc,
nullptr, textureResource.internalPointer()))) {
151 LOG_ERROR(logger,
"Failed to create resource (%s): %s", getString(textureDesc), direct3D11ReturnCodeAsString(hr));
155 LOG_TRACE(logger,
"Created resource %p: %s", textureResource.get<
void>(), getString(textureDesc));
158#if defined(OSOMP_EnableProfiler)
159 RegisterGPUResource(textureResource.get<
void>(), desc.estimateMemorySize(), MemBlockType::GPUTexture, profilerAttributes, 7);
162 texture.texture3D = textureResource;
166 graphicsDevice->getDevice()->GetImmediateContext(context.internalPointer());
170 rectangle.right = desc.width;
172 rectangle.bottom = desc.height;
174 rectangle.back = desc.depth;
175 context->UpdateSubresource(textureResource,
176 static_cast<UINT
>(0) * mipLevels,
179 static_cast<uint32_t
>(data->getPitch(0)),
180 static_cast<uint32_t
>(data->getPitch(0))*desc.height);
181 if(this->context->uploadStatisticsEnabled) this->context->uploadStatisticsTextureUpload(data->getSize());
185 D3D11_TEXTURE2D_DESC textureDesc = {};
186 textureDesc.Width = desc.width;
187 textureDesc.Height = desc.height;
188 textureDesc.ArraySize = desc.layers * desc.faces;
189 textureDesc.MipLevels = mipLevels;
190 textureDesc.Format = formatD3D;
191 textureDesc.SampleDesc.Count = desc.samples;
192 textureDesc.SampleDesc.Quality = 0;
193 textureDesc.Usage = usage;
194 textureDesc.BindFlags = bindFlags;
195 textureDesc.CPUAccessFlags = CPUAccessFlag;
202 if (desc.levels == 1 && generateMipmaps) {
203 if (FAILED(hr = graphicsDevice->getDevice()->CreateTexture2D(&textureDesc,
nullptr, textureResource.internalPointer()))) {
204 LOG_ERROR(logger,
"Failed to create resource (%s): %s", getString(textureDesc), direct3D11ReturnCodeAsString(hr));
208 LOG_TRACE(logger,
"Created resource %p: %s", textureResource.get<
void>(), getString(textureDesc));
211#if defined(OSOMP_EnableProfiler)
212 RegisterGPUResource(textureResource.get<
void>(), desc.estimateMemorySize(), MemBlockType::GPUTexture, profilerAttributes, 7);
216 graphicsDevice->getDevice()->GetImmediateContext(context.internalPointer());
218 for (
size_t i = 0; i < desc.layers; ++i) {
219 for (
size_t f = 0; f < desc.faces; f++) {
223 rectangle.right = desc.width;
225 rectangle.bottom = desc.height;
230 context->UpdateSubresource(textureResource,
231 static_cast<UINT
>(f + i*desc.faces) * mipLevels,
233 data->getData(i, f, 0),
234 static_cast<uint32_t
>(data->getPitch(0)), 1);
237 if(this->context->uploadStatisticsEnabled) this->context->uploadStatisticsTextureUpload(data->getSize());
240 textureDesc.MipLevels = desc.levels;
242 std::vector<D3D11_SUBRESOURCE_DATA> subresourceData(desc.layers * desc.faces * desc.levels);
243 auto pData = subresourceData.data();
245 for (
size_t i = 0; i < desc.layers; ++i) {
246 for (
size_t j = 0; j < desc.faces; ++j) {
247 for (
size_t k = 0; k < desc.levels; ++k) {
248 (*pData).pSysMem = data->getData(i, j, k);
249 (*pData).SysMemPitch =
static_cast<uint32_t
>(data->getPitch(k));
250 (*pData).SysMemSlicePitch = 0;
257 if (FAILED(hr = graphicsDevice->getDevice()->CreateTexture2D(&textureDesc, subresourceData.data(), textureResource.internalPointer()))) {
258 LOG_ERROR(logger,
"Failed to create resource (%s): %s", getString(textureDesc), direct3D11ReturnCodeAsString(hr));
262 LOG_TRACE(logger,
"Created resource %p: %s", textureResource.get<
void>(), getString(textureDesc));
264#if defined(OSOMP_EnableProfiler)
265 RegisterGPUResource(textureResource.get<
void>(), desc.estimateMemorySize(), MemBlockType::GPUTexture, profilerAttributes, 7);
270 if (FAILED(hr = graphicsDevice->getDevice()->CreateTexture2D(&textureDesc,
nullptr, textureResource.internalPointer()))) {
271 LOG_ERROR(logger,
"Failed to create resource (%s): %s", getString(textureDesc), direct3D11ReturnCodeAsString(hr));
275 LOG_DEBUG(logger,
"Created resource %p: %s", textureResource.get<
void>(), getString(textureDesc));
277#if defined(OSOMP_EnableProfiler)
278 RegisterGPUResource(textureResource.get<
void>(), desc.estimateMemorySize(), MemBlockType::GPUTexture, profilerAttributes, 7);
281 texture.texture2D = textureResource;
286 texture.shaderResourceView = createShaderResourceView(texture.resource(), flags);
289 D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
291 uavDesc.Format = formatD3D;
292 uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
293 uavDesc.Texture2D.MipSlice = 0;
295 hr = graphicsDevice->getDevice()->CreateUnorderedAccessView(texture.resource(), &uavDesc, texture.unorderedAccessView.internalPointer());
297 LOG_ERROR(logger,
"Failed to create unordered access view: %s", direct3D11ReturnCodeAsString(hr));
303 graphicsDevice->getDevice()->GetImmediateContext(context.internalPointer());
305 if (generateMipmaps) {
306 context->GenerateMips(texture.shaderResourceView);
310 textureMemoryConsumption += desc.estimateMemorySize();
311 return textures.addResource(std::move(texture));
316 if (!HandleIsValid(textureHandle)) {
return; }
321 LOG_TRACE(logger,
"Releasing resource %p", (
void*)(&texture));
325 textures.removeResource(textureHandle);
330 if (!HandleIsValid(view.
texture)) {
331 LOG_ERROR(logger,
"Cannot create texture view: Invalid texture");
336 LOG_ERROR(logger,
"Failed to create texture view.");
345 textureViews.removeResource(handle);
350 D3D11_RESOURCE_DIMENSION dimension;
351 resource->GetType(&dimension);
353 D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc = {};
357 case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
359 D3D11_TEXTURE2D_DESC textureDesc;
361 ((ID3D11Texture2D *)resource)->GetDesc(&textureDesc);
363 auto MostDetailedMip = std::min(mostDetailedMip, std::max(1u, textureDesc.MipLevels) - 1u);
364 auto MipLevels = std::min(mipLevels, std::max(mostDetailedMip, textureDesc.MipLevels) - mostDetailedMip);
366 resourceViewDesc.Format = textureDesc.Format;
368 if (textureDesc.Format == DXGI_FORMAT_R32_TYPELESS) {
369 resourceViewDesc.Format = DXGI_FORMAT_R32_FLOAT;
371 else if (textureDesc.Format == DXGI_FORMAT_R16_TYPELESS) {
372 resourceViewDesc.Format = DXGI_FORMAT_R16_UNORM;
374 else if (textureDesc.Format == DXGI_FORMAT_R8G8B8A8_TYPELESS) {
375 resourceViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
378 if (textureDesc.ArraySize == 1) {
379 if (textureDesc.SampleDesc.Count == 1) {
380 resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
381 resourceViewDesc.Texture2D.MipLevels = MipLevels;
382 resourceViewDesc.Texture2D.MostDetailedMip = MostDetailedMip;
385 resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
390 if (textureDesc.ArraySize == 6) {
391 resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
392 resourceViewDesc.TextureCube.MipLevels = MipLevels;
393 resourceViewDesc.TextureCube.MostDetailedMip = MostDetailedMip;
396 resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
397 resourceViewDesc.TextureCubeArray.MipLevels = MipLevels;
398 resourceViewDesc.TextureCubeArray.MostDetailedMip = MostDetailedMip;
399 resourceViewDesc.TextureCubeArray.NumCubes = textureDesc.ArraySize / 6;
400 resourceViewDesc.TextureCubeArray.First2DArrayFace = 0;
404 resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
405 resourceViewDesc.Texture2DArray.MipLevels = MipLevels;
406 resourceViewDesc.Texture2DArray.MostDetailedMip = MostDetailedMip;
407 resourceViewDesc.Texture2DArray.ArraySize = textureDesc.ArraySize;
408 resourceViewDesc.Texture2DArray.FirstArraySlice = 0;
414 case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
416 D3D11_TEXTURE3D_DESC textureDesc;
417 ((ID3D11Texture3D *)resource)->GetDesc(&textureDesc);
419 auto MostDetailedMip = std::min(mostDetailedMip, std::max(1u, textureDesc.MipLevels) - 1u);
420 auto MipLevels = std::min(mipLevels, std::max(mostDetailedMip, textureDesc.MipLevels) - mostDetailedMip);
422 resourceViewDesc.Format = textureDesc.Format;
424 if (textureDesc.Format == DXGI_FORMAT_R32_TYPELESS) {
425 resourceViewDesc.Format = DXGI_FORMAT_R32_FLOAT;
427 else if (textureDesc.Format == DXGI_FORMAT_R16_TYPELESS) {
428 resourceViewDesc.Format = DXGI_FORMAT_R16_UNORM;
430 else if (textureDesc.Format == DXGI_FORMAT_R8G8B8A8_TYPELESS) {
431 resourceViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
433 resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
434 resourceViewDesc.Texture3D.MipLevels = MipLevels;
435 resourceViewDesc.Texture3D.MostDetailedMip = MostDetailedMip;
439 LOG_ERROR(logger,
"Unsupported resource format for shader view.");
443 ResourcePointer<ID3D11ShaderResourceView> texture;
444 HRESULT hr = graphicsDevice->getDevice()->CreateShaderResourceView(resource, &resourceViewDesc, texture.internalPointer());
447 LOG_ERROR(logger,
"Failed to create shader resource view: %s", direct3D11ReturnCodeAsString(hr));
456 D3D11_SAMPLER_DESC samplerDesc = {};
458 samplerDesc.AddressU = Direct3D11::AddressModes[state.
addressModeS];
459 samplerDesc.AddressV = Direct3D11::AddressModes[state.
addressModeT];
460 samplerDesc.AddressW = Direct3D11::AddressModes[state.
addressModeW];
463 samplerDesc.Filter = D3D11_FILTER_ANISOTROPIC;
467 samplerDesc.Filter = Direct3D11::FilterModes[state.
filter];
470 samplerDesc.ComparisonFunc = Direct3D11::ComparisonFunctions[state.
comparisonFunction];
472 samplerDesc.MinLOD = std::numeric_limits<float>::lowest();
473 samplerDesc.MaxLOD = std::numeric_limits<float>::max();
475 for (
int i = 0; i < 4; ++i) {
480 HRESULT hr = graphicsDevice->getDevice()->CreateSamplerState(&samplerDesc, samplerState.internalPointer());
483 LOG_ERROR(logger,
"Failed to load sampler state: %s", direct3D11ReturnCodeAsString(hr));
487 return samplerStates.addResource(std::move(samplerState));
492 samplerStates.removeResource(handle);
497 return (
void*)(this->textures[textureHandle].resource());
504 graphicsDevice->getDevice()->GetImmediateContext(context.internalPointer());
506 context->GenerateMips(textures[textureHandle].shaderResourceView);
511 samplerStates.clear();
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
@ EnableTraceLogging
Enables trace logging.
static const Handle_t InvalidHandle
Represents an invalid handle.
Encapsulates state for texture sampling in a state object.
ComparisonFunction comparisonFunction
Specifies the comparison function to use when applying a comparison sampler.
unsigned int maxAnisotropy
Specifies the maximum number of anisotropic samples to use when sampling a texture.
AddressMode addressModeW
Specifies the addressing mode along the W axis in texture coordinate space.
AddressMode addressModeS
Specifies the addressing mode along the S axis in texture coordinate space.
FilterMode filter
Specifies the filter to use for texture sampling.
AddressMode addressModeT
Specifies the addressing mode along the T axis in texture coordinate space.
COGSRENDERING_DLL_API size_t estimateMemorySize() const
Attempts to estimate the amount of memory a texture with these attributes will require.
@ DepthBuffer
The texture can be used as a depth target and have depth buffer values written into.
@ RenderTarget
The texture can be used as a render target and drawn into.
@ GenerateMipMaps
The texture supports automatic mipmap generation performed by the graphics device.
@ Texture
Texture usage, see Default.
@ ReadWriteTexture
The texture can be used as a read/write texture. Can be used to output data from compute shaders.
@ UsageReadStaging
The texture is intended to be used as a staging texture.
@ CubeMap
The texture can be used as a cube map.
Describes how to fetch data from a texture in shaders.
uint32_t numLevels
Number of mipmap levels available.
uint32_t levelIndex
First mipmap level to fetch data from.
TextureHandle texture
Texture.
void releaseResources() override
Release all allocated texture resources.
SamplerStateHandle loadSamplerState(const SamplerState &state) override
Load a sampler state object.
void releaseTextureView(const TextureViewHandle &handle) override
Release the given texture view.
TextureHandle loadTexture(const TextureDescription &desc, const TextureData *data) override
Load a texture from the given description.
void generateMipmaps(TextureHandle texureHandle) override
Use the graphics device to generate mipmaps for the texture with the given texture handle.
void * getNativeHandle(TextureHandle textureHandle) override
Get the device-specific handle (D3D texture pointer, OpenGL texture ID etc) associated with the given...
void releaseSamplerState(SamplerStateHandle handle) override
Release the sampler state with the given handle.
void releaseTexture(TextureHandle textureHandle) override
Release the texture with the given textureHandle.
TextureViewHandle createTextureView(TextureViewDescription &view) override
Create a texture view used to bind a limited view of the texture data to the rendering pipeline.
void annotate(TextureHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.