ResourceManager11.cpp (19000B)
1 // 2 // Copyright 2017 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 // ResourceManager11: 7 // Centralized point of allocation for all D3D11 Resources. 8 9 #include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" 10 11 #include "common/debug.h" 12 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" 13 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" 14 15 namespace rx 16 { 17 18 namespace 19 { 20 21 constexpr uint8_t kDebugInitTextureDataValue = 0x48; 22 constexpr FLOAT kDebugColorInitClearValue[4] = {0.3f, 0.5f, 0.7f, 0.5f}; 23 constexpr FLOAT kDebugDepthInitValue = 0.2f; 24 constexpr UINT8 kDebugStencilInitValue = 3; 25 26 // A hard limit on buffer size. This works around a problem in the NVIDIA drivers where buffer sizes 27 // close to MAX_UINT would give undefined results. The limit of MAX_UINT/2 should be generous enough 28 // for almost any demanding application. 29 constexpr UINT kMaximumBufferSizeHardLimit = std::numeric_limits<UINT>::max() >> 1; 30 31 uint64_t ComputeMippedMemoryUsage(unsigned int width, 32 unsigned int height, 33 unsigned int depth, 34 uint64_t pixelSize, 35 unsigned int mipLevels) 36 { 37 uint64_t sizeSum = 0; 38 39 for (unsigned int level = 0; level < mipLevels; ++level) 40 { 41 unsigned int mipWidth = std::max(width >> level, 1u); 42 unsigned int mipHeight = std::max(height >> level, 1u); 43 unsigned int mipDepth = std::max(depth >> level, 1u); 44 sizeSum += static_cast<uint64_t>(mipWidth * mipHeight * mipDepth) * pixelSize; 45 } 46 47 return sizeSum; 48 } 49 50 uint64_t ComputeMemoryUsage(const D3D11_TEXTURE2D_DESC *desc) 51 { 52 ASSERT(desc); 53 uint64_t pixelBytes = 54 static_cast<uint64_t>(d3d11::GetDXGIFormatSizeInfo(desc->Format).pixelBytes); 55 return ComputeMippedMemoryUsage(desc->Width, desc->Height, 1, pixelBytes, desc->MipLevels); 56 } 57 58 uint64_t ComputeMemoryUsage(const D3D11_TEXTURE3D_DESC *desc) 59 { 60 ASSERT(desc); 61 uint64_t pixelBytes = 62 static_cast<uint64_t>(d3d11::GetDXGIFormatSizeInfo(desc->Format).pixelBytes); 63 return ComputeMippedMemoryUsage(desc->Width, desc->Height, desc->Depth, pixelBytes, 64 desc->MipLevels); 65 } 66 67 uint64_t ComputeMemoryUsage(const D3D11_BUFFER_DESC *desc) 68 { 69 ASSERT(desc); 70 return static_cast<uint64_t>(desc->ByteWidth); 71 } 72 73 template <typename T> 74 uint64_t ComputeMemoryUsage(const T *desc) 75 { 76 return 0; 77 } 78 79 template <ResourceType ResourceT> 80 uint64_t ComputeGenericMemoryUsage(ID3D11DeviceChild *genericResource) 81 { 82 auto *typedResource = static_cast<GetD3D11Type<ResourceT> *>(genericResource); 83 GetDescType<ResourceT> desc; 84 typedResource->GetDesc(&desc); 85 return ComputeMemoryUsage(&desc); 86 } 87 88 uint64_t ComputeGenericMemoryUsage(ResourceType resourceType, ID3D11DeviceChild *resource) 89 { 90 switch (resourceType) 91 { 92 case ResourceType::Texture2D: 93 return ComputeGenericMemoryUsage<ResourceType::Texture2D>(resource); 94 case ResourceType::Texture3D: 95 return ComputeGenericMemoryUsage<ResourceType::Texture3D>(resource); 96 case ResourceType::Buffer: 97 return ComputeGenericMemoryUsage<ResourceType::Buffer>(resource); 98 99 default: 100 return 0; 101 } 102 } 103 104 HRESULT CreateResource(ID3D11Device *device, 105 const D3D11_BLEND_DESC *desc, 106 void * /*initData*/, 107 ID3D11BlendState **blendState) 108 { 109 return device->CreateBlendState(desc, blendState); 110 } 111 112 HRESULT CreateResource(ID3D11Device *device, 113 const D3D11_BUFFER_DESC *desc, 114 const D3D11_SUBRESOURCE_DATA *initData, 115 ID3D11Buffer **buffer) 116 { 117 // Force buffers to be limited to a fixed max size. 118 if (desc->ByteWidth > kMaximumBufferSizeHardLimit) 119 { 120 return E_OUTOFMEMORY; 121 } 122 123 return device->CreateBuffer(desc, initData, buffer); 124 } 125 126 HRESULT CreateResource(ID3D11Device *device, 127 const ShaderData *desc, 128 void * /*initData*/, 129 ID3D11ComputeShader **resourceOut) 130 { 131 return device->CreateComputeShader(desc->get(), desc->size(), nullptr, resourceOut); 132 } 133 134 HRESULT CreateResource(ID3D11Device *device, 135 const D3D11_DEPTH_STENCIL_DESC *desc, 136 void * /*initData*/, 137 ID3D11DepthStencilState **resourceOut) 138 { 139 return device->CreateDepthStencilState(desc, resourceOut); 140 } 141 142 HRESULT CreateResource(ID3D11Device *device, 143 const D3D11_DEPTH_STENCIL_VIEW_DESC *desc, 144 ID3D11Resource *resource, 145 ID3D11DepthStencilView **resourceOut) 146 { 147 return device->CreateDepthStencilView(resource, desc, resourceOut); 148 } 149 150 HRESULT CreateResource(ID3D11Device *device, 151 const ShaderData *desc, 152 const std::vector<D3D11_SO_DECLARATION_ENTRY> *initData, 153 ID3D11GeometryShader **resourceOut) 154 { 155 if (initData) 156 { 157 return device->CreateGeometryShaderWithStreamOutput( 158 desc->get(), desc->size(), initData->data(), static_cast<UINT>(initData->size()), 159 nullptr, 0, 0, nullptr, resourceOut); 160 } 161 else 162 { 163 return device->CreateGeometryShader(desc->get(), desc->size(), nullptr, resourceOut); 164 } 165 } 166 167 HRESULT CreateResource(ID3D11Device *device, 168 const InputElementArray *desc, 169 const ShaderData *initData, 170 ID3D11InputLayout **resourceOut) 171 { 172 return device->CreateInputLayout(desc->get(), static_cast<UINT>(desc->size()), initData->get(), 173 initData->size(), resourceOut); 174 } 175 176 HRESULT CreateResource(ID3D11Device *device, 177 const ShaderData *desc, 178 void * /*initData*/, 179 ID3D11PixelShader **resourceOut) 180 { 181 return device->CreatePixelShader(desc->get(), desc->size(), nullptr, resourceOut); 182 } 183 184 HRESULT CreateResource(ID3D11Device *device, 185 const D3D11_QUERY_DESC *desc, 186 void * /*initData*/, 187 ID3D11Query **resourceOut) 188 { 189 return device->CreateQuery(desc, resourceOut); 190 } 191 192 HRESULT CreateResource(ID3D11Device *device, 193 const D3D11_RASTERIZER_DESC *desc, 194 void * /*initData*/, 195 ID3D11RasterizerState **rasterizerState) 196 { 197 return device->CreateRasterizerState(desc, rasterizerState); 198 } 199 200 HRESULT CreateResource(ID3D11Device *device, 201 const D3D11_RENDER_TARGET_VIEW_DESC *desc, 202 ID3D11Resource *resource, 203 ID3D11RenderTargetView **renderTargetView) 204 { 205 return device->CreateRenderTargetView(resource, desc, renderTargetView); 206 } 207 208 HRESULT CreateResource(ID3D11Device *device, 209 const D3D11_SAMPLER_DESC *desc, 210 void * /*initData*/, 211 ID3D11SamplerState **resourceOut) 212 { 213 return device->CreateSamplerState(desc, resourceOut); 214 } 215 216 HRESULT CreateResource(ID3D11Device *device, 217 const D3D11_SHADER_RESOURCE_VIEW_DESC *desc, 218 ID3D11Resource *resource, 219 ID3D11ShaderResourceView **resourceOut) 220 { 221 return device->CreateShaderResourceView(resource, desc, resourceOut); 222 } 223 224 HRESULT CreateResource(ID3D11Device *device, 225 const D3D11_UNORDERED_ACCESS_VIEW_DESC *desc, 226 ID3D11Resource *resource, 227 ID3D11UnorderedAccessView **resourceOut) 228 { 229 return device->CreateUnorderedAccessView(resource, desc, resourceOut); 230 } 231 232 HRESULT CreateResource(ID3D11Device *device, 233 const D3D11_TEXTURE2D_DESC *desc, 234 const D3D11_SUBRESOURCE_DATA *initData, 235 ID3D11Texture2D **texture) 236 { 237 return device->CreateTexture2D(desc, initData, texture); 238 } 239 240 HRESULT CreateResource(ID3D11Device *device, 241 const D3D11_TEXTURE3D_DESC *desc, 242 const D3D11_SUBRESOURCE_DATA *initData, 243 ID3D11Texture3D **texture) 244 { 245 return device->CreateTexture3D(desc, initData, texture); 246 } 247 248 HRESULT CreateResource(ID3D11Device *device, 249 const ShaderData *desc, 250 void * /*initData*/, 251 ID3D11VertexShader **resourceOut) 252 { 253 return device->CreateVertexShader(desc->get(), desc->size(), nullptr, resourceOut); 254 } 255 256 DXGI_FORMAT GetTypedDepthStencilFormat(DXGI_FORMAT dxgiFormat) 257 { 258 switch (dxgiFormat) 259 { 260 case DXGI_FORMAT_R16_TYPELESS: 261 return DXGI_FORMAT_D16_UNORM; 262 case DXGI_FORMAT_R24G8_TYPELESS: 263 return DXGI_FORMAT_D24_UNORM_S8_UINT; 264 case DXGI_FORMAT_R32_TYPELESS: 265 return DXGI_FORMAT_D32_FLOAT; 266 case DXGI_FORMAT_R32G8X24_TYPELESS: 267 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; 268 default: 269 return dxgiFormat; 270 } 271 } 272 273 template <typename DescT, typename ResourceT> 274 angle::Result ClearResource(d3d::Context *context, 275 Renderer11 *renderer, 276 const DescT *desc, 277 ResourceT *texture) 278 { 279 // No-op. 280 return angle::Result::Continue; 281 } 282 283 template <> 284 angle::Result ClearResource(d3d::Context *context, 285 Renderer11 *renderer, 286 const D3D11_TEXTURE2D_DESC *desc, 287 ID3D11Texture2D *texture) 288 { 289 ID3D11DeviceContext *deviceContext = renderer->getDeviceContext(); 290 291 if ((desc->BindFlags & D3D11_BIND_DEPTH_STENCIL) != 0) 292 { 293 D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; 294 dsvDesc.Flags = 0; 295 dsvDesc.Format = GetTypedDepthStencilFormat(desc->Format); 296 297 const auto &format = d3d11_angle::GetFormat(dsvDesc.Format); 298 UINT clearFlags = (format.depthBits > 0 ? D3D11_CLEAR_DEPTH : 0) | 299 (format.stencilBits > 0 ? D3D11_CLEAR_STENCIL : 0); 300 301 // Must process each mip level individually. 302 for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel) 303 { 304 if (desc->SampleDesc.Count == 0) 305 { 306 dsvDesc.Texture2D.MipSlice = mipLevel; 307 dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; 308 } 309 else 310 { 311 dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; 312 } 313 314 d3d11::DepthStencilView dsv; 315 ANGLE_TRY(renderer->allocateResource(context, dsvDesc, texture, &dsv)); 316 317 deviceContext->ClearDepthStencilView(dsv.get(), clearFlags, kDebugDepthInitValue, 318 kDebugStencilInitValue); 319 } 320 } 321 else 322 { 323 ASSERT((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0); 324 d3d11::RenderTargetView rtv; 325 ANGLE_TRY(renderer->allocateResourceNoDesc(context, texture, &rtv)); 326 327 deviceContext->ClearRenderTargetView(rtv.get(), kDebugColorInitClearValue); 328 } 329 330 return angle::Result::Continue; 331 } 332 333 template <> 334 angle::Result ClearResource(d3d::Context *context, 335 Renderer11 *renderer, 336 const D3D11_TEXTURE3D_DESC *desc, 337 ID3D11Texture3D *texture) 338 { 339 ID3D11DeviceContext *deviceContext = renderer->getDeviceContext(); 340 341 ASSERT((desc->BindFlags & D3D11_BIND_DEPTH_STENCIL) == 0); 342 ASSERT((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0); 343 344 d3d11::RenderTargetView rtv; 345 ANGLE_TRY(renderer->allocateResourceNoDesc(context, texture, &rtv)); 346 347 deviceContext->ClearRenderTargetView(rtv.get(), kDebugColorInitClearValue); 348 return angle::Result::Continue; 349 } 350 351 #define ANGLE_RESOURCE_STRINGIFY_OP(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ 352 "Error allocating " #RESTYPE, 353 354 constexpr std::array<const char *, NumResourceTypes> kResourceTypeErrors = { 355 {ANGLE_RESOURCE_TYPE_OP(Stringify, ANGLE_RESOURCE_STRINGIFY_OP)}}; 356 static_assert(kResourceTypeErrors[NumResourceTypes - 1] != nullptr, 357 "All members must be initialized."); 358 359 } // anonymous namespace 360 361 // ResourceManager11 Implementation. 362 ResourceManager11::ResourceManager11() : mInitializeAllocations(false) 363 { 364 for (auto &count : mAllocatedResourceCounts) 365 { 366 count = 0; 367 } 368 for (auto &memorySize : mAllocatedResourceDeviceMemory) 369 { 370 memorySize = 0; 371 } 372 } 373 374 ResourceManager11::~ResourceManager11() 375 { 376 for (size_t count : mAllocatedResourceCounts) 377 { 378 ASSERT(count == 0); 379 } 380 381 for (uint64_t memorySize : mAllocatedResourceDeviceMemory) 382 { 383 ASSERT(memorySize == 0); 384 } 385 } 386 387 template <typename T> 388 angle::Result ResourceManager11::allocate(d3d::Context *context, 389 Renderer11 *renderer, 390 const GetDescFromD3D11<T> *desc, 391 GetInitDataFromD3D11<T> *initData, 392 Resource11<T> *resourceOut) 393 { 394 ID3D11Device *device = renderer->getDevice(); 395 T *resource = nullptr; 396 397 GetInitDataFromD3D11<T> *shadowInitData = initData; 398 if (!shadowInitData && mInitializeAllocations) 399 { 400 shadowInitData = createInitDataIfNeeded<T>(desc); 401 } 402 403 HRESULT hr = CreateResource(device, desc, shadowInitData, &resource); 404 ANGLE_TRY_HR(context, hr, kResourceTypeErrors[ResourceTypeIndex<T>()]); 405 406 if (!shadowInitData && mInitializeAllocations) 407 { 408 ANGLE_TRY(ClearResource(context, renderer, desc, resource)); 409 } 410 411 ASSERT(resource); 412 incrResource(GetResourceTypeFromD3D11<T>(), ComputeMemoryUsage(desc)); 413 *resourceOut = std::move(Resource11<T>(resource, this)); 414 return angle::Result::Continue; 415 } 416 417 void ResourceManager11::incrResource(ResourceType resourceType, uint64_t memorySize) 418 { 419 size_t typeIndex = ResourceTypeIndex(resourceType); 420 421 mAllocatedResourceCounts[typeIndex]++; 422 mAllocatedResourceDeviceMemory[typeIndex] += memorySize; 423 424 // This checks for integer overflow. 425 ASSERT(mAllocatedResourceCounts[typeIndex] > 0); 426 ASSERT(mAllocatedResourceDeviceMemory[typeIndex] >= memorySize); 427 } 428 429 void ResourceManager11::decrResource(ResourceType resourceType, uint64_t memorySize) 430 { 431 size_t typeIndex = ResourceTypeIndex(resourceType); 432 433 ASSERT(mAllocatedResourceCounts[typeIndex] > 0); 434 mAllocatedResourceCounts[typeIndex]--; 435 ASSERT(mAllocatedResourceDeviceMemory[typeIndex] >= memorySize); 436 mAllocatedResourceDeviceMemory[typeIndex] -= memorySize; 437 } 438 439 void ResourceManager11::onReleaseGeneric(ResourceType resourceType, ID3D11DeviceChild *resource) 440 { 441 ASSERT(resource); 442 decrResource(resourceType, ComputeGenericMemoryUsage(resourceType, resource)); 443 } 444 445 template <> 446 const D3D11_SUBRESOURCE_DATA *ResourceManager11::createInitDataIfNeeded<ID3D11Texture2D>( 447 const D3D11_TEXTURE2D_DESC *desc) 448 { 449 ASSERT(desc); 450 451 if ((desc->BindFlags & (D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_RENDER_TARGET)) != 0) 452 { 453 // This will be done using ClearView methods. 454 return nullptr; 455 } 456 457 size_t requiredSize = static_cast<size_t>(ComputeMemoryUsage(desc)); 458 if (mZeroMemory.size() < requiredSize) 459 { 460 if (!mZeroMemory.resize(requiredSize)) 461 { 462 ERR() << "Failed to allocate D3D texture initialization data."; 463 return nullptr; 464 } 465 mZeroMemory.fill(kDebugInitTextureDataValue); 466 } 467 468 const auto &formatSizeInfo = d3d11::GetDXGIFormatSizeInfo(desc->Format); 469 470 UINT subresourceCount = desc->MipLevels * desc->ArraySize; 471 if (mShadowInitData.size() < subresourceCount) 472 { 473 mShadowInitData.resize(subresourceCount); 474 } 475 476 for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel) 477 { 478 for (UINT arrayIndex = 0; arrayIndex < desc->ArraySize; ++arrayIndex) 479 { 480 UINT subresourceIndex = D3D11CalcSubresource(mipLevel, arrayIndex, desc->MipLevels); 481 D3D11_SUBRESOURCE_DATA *data = &mShadowInitData[subresourceIndex]; 482 483 UINT levelWidth = std::max(desc->Width >> mipLevel, 1u); 484 UINT levelHeight = std::max(desc->Height >> mipLevel, 1u); 485 486 data->SysMemPitch = levelWidth * formatSizeInfo.pixelBytes; 487 data->SysMemSlicePitch = data->SysMemPitch * levelHeight; 488 data->pSysMem = mZeroMemory.data(); 489 } 490 } 491 492 return mShadowInitData.data(); 493 } 494 495 template <> 496 const D3D11_SUBRESOURCE_DATA *ResourceManager11::createInitDataIfNeeded<ID3D11Texture3D>( 497 const D3D11_TEXTURE3D_DESC *desc) 498 { 499 ASSERT(desc); 500 501 if ((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0) 502 { 503 // This will be done using ClearView methods. 504 return nullptr; 505 } 506 507 size_t requiredSize = static_cast<size_t>(ComputeMemoryUsage(desc)); 508 if (mZeroMemory.size() < requiredSize) 509 { 510 if (!mZeroMemory.resize(requiredSize)) 511 { 512 ERR() << "Failed to allocate D3D texture initialization data."; 513 return nullptr; 514 } 515 mZeroMemory.fill(kDebugInitTextureDataValue); 516 } 517 518 const auto &formatSizeInfo = d3d11::GetDXGIFormatSizeInfo(desc->Format); 519 520 UINT subresourceCount = desc->MipLevels; 521 if (mShadowInitData.size() < subresourceCount) 522 { 523 mShadowInitData.resize(subresourceCount); 524 } 525 526 for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel) 527 { 528 UINT subresourceIndex = D3D11CalcSubresource(mipLevel, 0, desc->MipLevels); 529 D3D11_SUBRESOURCE_DATA *data = &mShadowInitData[subresourceIndex]; 530 531 UINT levelWidth = std::max(desc->Width >> mipLevel, 1u); 532 UINT levelHeight = std::max(desc->Height >> mipLevel, 1u); 533 534 data->SysMemPitch = levelWidth * formatSizeInfo.pixelBytes; 535 data->SysMemSlicePitch = data->SysMemPitch * levelHeight; 536 data->pSysMem = mZeroMemory.data(); 537 } 538 539 return mShadowInitData.data(); 540 } 541 542 template <typename T> 543 GetInitDataFromD3D11<T> *ResourceManager11::createInitDataIfNeeded(const GetDescFromD3D11<T> *desc) 544 { 545 // No-op. 546 return nullptr; 547 } 548 549 void ResourceManager11::setAllocationsInitialized(bool initialize) 550 { 551 mInitializeAllocations = initialize; 552 } 553 554 #define ANGLE_INSTANTIATE_OP(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ 555 \ 556 template angle::Result ResourceManager11::allocate( \ 557 d3d::Context *, Renderer11 *, const DESCTYPE *, INITDATATYPE *, Resource11<D3D11TYPE> *); 558 559 ANGLE_RESOURCE_TYPE_OP(Instantitate, ANGLE_INSTANTIATE_OP) 560 } // namespace rx