1 // Copyright 2017 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "dawn_native/d3d12/TextureD3D12.h" 16 17 #include "common/Constants.h" 18 #include "common/Math.h" 19 #include "dawn_native/DynamicUploader.h" 20 #include "dawn_native/EnumMaskIterator.h" 21 #include "dawn_native/Error.h" 22 #include "dawn_native/d3d12/BufferD3D12.h" 23 #include "dawn_native/d3d12/CommandRecordingContext.h" 24 #include "dawn_native/d3d12/D3D12Error.h" 25 #include "dawn_native/d3d12/DeviceD3D12.h" 26 #include "dawn_native/d3d12/HeapD3D12.h" 27 #include "dawn_native/d3d12/ResourceAllocatorManagerD3D12.h" 28 #include "dawn_native/d3d12/StagingBufferD3D12.h" 29 #include "dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h" 30 #include "dawn_native/d3d12/TextureCopySplitter.h" 31 #include "dawn_native/d3d12/UtilsD3D12.h" 32 33 namespace dawn_native { namespace d3d12 { 34 35 namespace { D3D12TextureUsage(wgpu::TextureUsage usage,const Format & format)36 D3D12_RESOURCE_STATES D3D12TextureUsage(wgpu::TextureUsage usage, const Format& format) { 37 D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_COMMON; 38 39 if (usage & kPresentTextureUsage) { 40 // The present usage is only used internally by the swapchain and is never used in 41 // combination with other usages. 42 ASSERT(usage == kPresentTextureUsage); 43 return D3D12_RESOURCE_STATE_PRESENT; 44 } 45 46 if (usage & wgpu::TextureUsage::CopySrc) { 47 resourceState |= D3D12_RESOURCE_STATE_COPY_SOURCE; 48 } 49 if (usage & wgpu::TextureUsage::CopyDst) { 50 resourceState |= D3D12_RESOURCE_STATE_COPY_DEST; 51 } 52 if (usage & (wgpu::TextureUsage::Sampled | kReadonlyStorageTexture)) { 53 resourceState |= (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | 54 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); 55 } 56 if (usage & wgpu::TextureUsage::Storage) { 57 resourceState |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS; 58 } 59 if (usage & wgpu::TextureUsage::RenderAttachment) { 60 if (format.HasDepthOrStencil()) { 61 resourceState |= D3D12_RESOURCE_STATE_DEPTH_WRITE; 62 } else { 63 resourceState |= D3D12_RESOURCE_STATE_RENDER_TARGET; 64 } 65 } 66 67 return resourceState; 68 } 69 D3D12ResourceFlags(wgpu::TextureUsage usage,const Format & format,bool isMultisampledTexture)70 D3D12_RESOURCE_FLAGS D3D12ResourceFlags(wgpu::TextureUsage usage, 71 const Format& format, 72 bool isMultisampledTexture) { 73 D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE; 74 75 if (usage & wgpu::TextureUsage::Storage) { 76 flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; 77 } 78 79 // A multisampled resource must have either D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET or 80 // D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL set in D3D12_RESOURCE_DESC::Flags. 81 // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_resource_desc 82 if ((usage & wgpu::TextureUsage::RenderAttachment) != 0 || isMultisampledTexture) { 83 if (format.HasDepthOrStencil()) { 84 flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; 85 } else { 86 flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; 87 } 88 } 89 90 ASSERT(!(flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) || 91 flags == D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); 92 return flags; 93 } 94 D3D12TextureDimension(wgpu::TextureDimension dimension)95 D3D12_RESOURCE_DIMENSION D3D12TextureDimension(wgpu::TextureDimension dimension) { 96 switch (dimension) { 97 case wgpu::TextureDimension::e2D: 98 return D3D12_RESOURCE_DIMENSION_TEXTURE2D; 99 100 case wgpu::TextureDimension::e1D: 101 case wgpu::TextureDimension::e3D: 102 UNREACHABLE(); 103 } 104 } 105 D3D12TypelessTextureFormat(wgpu::TextureFormat format)106 DXGI_FORMAT D3D12TypelessTextureFormat(wgpu::TextureFormat format) { 107 switch (format) { 108 case wgpu::TextureFormat::R8Unorm: 109 case wgpu::TextureFormat::R8Snorm: 110 case wgpu::TextureFormat::R8Uint: 111 case wgpu::TextureFormat::R8Sint: 112 return DXGI_FORMAT_R8_TYPELESS; 113 114 case wgpu::TextureFormat::R16Uint: 115 case wgpu::TextureFormat::R16Sint: 116 case wgpu::TextureFormat::R16Float: 117 return DXGI_FORMAT_R16_TYPELESS; 118 119 case wgpu::TextureFormat::RG8Unorm: 120 case wgpu::TextureFormat::RG8Snorm: 121 case wgpu::TextureFormat::RG8Uint: 122 case wgpu::TextureFormat::RG8Sint: 123 return DXGI_FORMAT_R8G8_TYPELESS; 124 125 case wgpu::TextureFormat::R32Uint: 126 case wgpu::TextureFormat::R32Sint: 127 case wgpu::TextureFormat::R32Float: 128 return DXGI_FORMAT_R32_TYPELESS; 129 130 case wgpu::TextureFormat::RG16Uint: 131 case wgpu::TextureFormat::RG16Sint: 132 case wgpu::TextureFormat::RG16Float: 133 return DXGI_FORMAT_R16G16_TYPELESS; 134 135 case wgpu::TextureFormat::RGBA8Unorm: 136 case wgpu::TextureFormat::RGBA8UnormSrgb: 137 case wgpu::TextureFormat::RGBA8Snorm: 138 case wgpu::TextureFormat::RGBA8Uint: 139 case wgpu::TextureFormat::RGBA8Sint: 140 return DXGI_FORMAT_R8G8B8A8_TYPELESS; 141 142 case wgpu::TextureFormat::BGRA8Unorm: 143 case wgpu::TextureFormat::BGRA8UnormSrgb: 144 return DXGI_FORMAT_B8G8R8A8_TYPELESS; 145 146 case wgpu::TextureFormat::RGB10A2Unorm: 147 return DXGI_FORMAT_R10G10B10A2_TYPELESS; 148 149 case wgpu::TextureFormat::RG11B10Ufloat: 150 return DXGI_FORMAT_R11G11B10_FLOAT; 151 case wgpu::TextureFormat::RGB9E5Ufloat: 152 return DXGI_FORMAT_R9G9B9E5_SHAREDEXP; 153 154 case wgpu::TextureFormat::RG32Uint: 155 case wgpu::TextureFormat::RG32Sint: 156 case wgpu::TextureFormat::RG32Float: 157 return DXGI_FORMAT_R32G32_TYPELESS; 158 159 case wgpu::TextureFormat::RGBA16Uint: 160 case wgpu::TextureFormat::RGBA16Sint: 161 case wgpu::TextureFormat::RGBA16Float: 162 return DXGI_FORMAT_R16G16B16A16_TYPELESS; 163 164 case wgpu::TextureFormat::RGBA32Uint: 165 case wgpu::TextureFormat::RGBA32Sint: 166 case wgpu::TextureFormat::RGBA32Float: 167 return DXGI_FORMAT_R32G32B32A32_TYPELESS; 168 169 case wgpu::TextureFormat::Depth32Float: 170 case wgpu::TextureFormat::Depth24Plus: 171 return DXGI_FORMAT_R32_TYPELESS; 172 173 case wgpu::TextureFormat::Depth24PlusStencil8: 174 return DXGI_FORMAT_R32G8X24_TYPELESS; 175 176 case wgpu::TextureFormat::BC1RGBAUnorm: 177 case wgpu::TextureFormat::BC1RGBAUnormSrgb: 178 return DXGI_FORMAT_BC1_TYPELESS; 179 180 case wgpu::TextureFormat::BC2RGBAUnorm: 181 case wgpu::TextureFormat::BC2RGBAUnormSrgb: 182 return DXGI_FORMAT_BC2_TYPELESS; 183 184 case wgpu::TextureFormat::BC3RGBAUnorm: 185 case wgpu::TextureFormat::BC3RGBAUnormSrgb: 186 return DXGI_FORMAT_BC3_TYPELESS; 187 188 case wgpu::TextureFormat::BC4RSnorm: 189 case wgpu::TextureFormat::BC4RUnorm: 190 return DXGI_FORMAT_BC4_TYPELESS; 191 192 case wgpu::TextureFormat::BC5RGSnorm: 193 case wgpu::TextureFormat::BC5RGUnorm: 194 return DXGI_FORMAT_BC5_TYPELESS; 195 196 case wgpu::TextureFormat::BC6HRGBFloat: 197 case wgpu::TextureFormat::BC6HRGBUfloat: 198 return DXGI_FORMAT_BC6H_TYPELESS; 199 200 case wgpu::TextureFormat::BC7RGBAUnorm: 201 case wgpu::TextureFormat::BC7RGBAUnormSrgb: 202 return DXGI_FORMAT_BC7_TYPELESS; 203 204 case wgpu::TextureFormat::Undefined: 205 UNREACHABLE(); 206 } 207 } 208 209 } // namespace 210 D3D12TextureFormat(wgpu::TextureFormat format)211 DXGI_FORMAT D3D12TextureFormat(wgpu::TextureFormat format) { 212 switch (format) { 213 case wgpu::TextureFormat::R8Unorm: 214 return DXGI_FORMAT_R8_UNORM; 215 case wgpu::TextureFormat::R8Snorm: 216 return DXGI_FORMAT_R8_SNORM; 217 case wgpu::TextureFormat::R8Uint: 218 return DXGI_FORMAT_R8_UINT; 219 case wgpu::TextureFormat::R8Sint: 220 return DXGI_FORMAT_R8_SINT; 221 222 case wgpu::TextureFormat::R16Uint: 223 return DXGI_FORMAT_R16_UINT; 224 case wgpu::TextureFormat::R16Sint: 225 return DXGI_FORMAT_R16_SINT; 226 case wgpu::TextureFormat::R16Float: 227 return DXGI_FORMAT_R16_FLOAT; 228 case wgpu::TextureFormat::RG8Unorm: 229 return DXGI_FORMAT_R8G8_UNORM; 230 case wgpu::TextureFormat::RG8Snorm: 231 return DXGI_FORMAT_R8G8_SNORM; 232 case wgpu::TextureFormat::RG8Uint: 233 return DXGI_FORMAT_R8G8_UINT; 234 case wgpu::TextureFormat::RG8Sint: 235 return DXGI_FORMAT_R8G8_SINT; 236 237 case wgpu::TextureFormat::R32Uint: 238 return DXGI_FORMAT_R32_UINT; 239 case wgpu::TextureFormat::R32Sint: 240 return DXGI_FORMAT_R32_SINT; 241 case wgpu::TextureFormat::R32Float: 242 return DXGI_FORMAT_R32_FLOAT; 243 case wgpu::TextureFormat::RG16Uint: 244 return DXGI_FORMAT_R16G16_UINT; 245 case wgpu::TextureFormat::RG16Sint: 246 return DXGI_FORMAT_R16G16_SINT; 247 case wgpu::TextureFormat::RG16Float: 248 return DXGI_FORMAT_R16G16_FLOAT; 249 case wgpu::TextureFormat::RGBA8Unorm: 250 return DXGI_FORMAT_R8G8B8A8_UNORM; 251 case wgpu::TextureFormat::RGBA8UnormSrgb: 252 return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; 253 case wgpu::TextureFormat::RGBA8Snorm: 254 return DXGI_FORMAT_R8G8B8A8_SNORM; 255 case wgpu::TextureFormat::RGBA8Uint: 256 return DXGI_FORMAT_R8G8B8A8_UINT; 257 case wgpu::TextureFormat::RGBA8Sint: 258 return DXGI_FORMAT_R8G8B8A8_SINT; 259 case wgpu::TextureFormat::BGRA8Unorm: 260 return DXGI_FORMAT_B8G8R8A8_UNORM; 261 case wgpu::TextureFormat::BGRA8UnormSrgb: 262 return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; 263 case wgpu::TextureFormat::RGB10A2Unorm: 264 return DXGI_FORMAT_R10G10B10A2_UNORM; 265 case wgpu::TextureFormat::RG11B10Ufloat: 266 return DXGI_FORMAT_R11G11B10_FLOAT; 267 case wgpu::TextureFormat::RGB9E5Ufloat: 268 return DXGI_FORMAT_R9G9B9E5_SHAREDEXP; 269 270 case wgpu::TextureFormat::RG32Uint: 271 return DXGI_FORMAT_R32G32_UINT; 272 case wgpu::TextureFormat::RG32Sint: 273 return DXGI_FORMAT_R32G32_SINT; 274 case wgpu::TextureFormat::RG32Float: 275 return DXGI_FORMAT_R32G32_FLOAT; 276 case wgpu::TextureFormat::RGBA16Uint: 277 return DXGI_FORMAT_R16G16B16A16_UINT; 278 case wgpu::TextureFormat::RGBA16Sint: 279 return DXGI_FORMAT_R16G16B16A16_SINT; 280 case wgpu::TextureFormat::RGBA16Float: 281 return DXGI_FORMAT_R16G16B16A16_FLOAT; 282 283 case wgpu::TextureFormat::RGBA32Uint: 284 return DXGI_FORMAT_R32G32B32A32_UINT; 285 case wgpu::TextureFormat::RGBA32Sint: 286 return DXGI_FORMAT_R32G32B32A32_SINT; 287 case wgpu::TextureFormat::RGBA32Float: 288 return DXGI_FORMAT_R32G32B32A32_FLOAT; 289 290 case wgpu::TextureFormat::Depth32Float: 291 return DXGI_FORMAT_D32_FLOAT; 292 case wgpu::TextureFormat::Depth24Plus: 293 return DXGI_FORMAT_D32_FLOAT; 294 case wgpu::TextureFormat::Depth24PlusStencil8: 295 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; 296 297 case wgpu::TextureFormat::BC1RGBAUnorm: 298 return DXGI_FORMAT_BC1_UNORM; 299 case wgpu::TextureFormat::BC1RGBAUnormSrgb: 300 return DXGI_FORMAT_BC1_UNORM_SRGB; 301 case wgpu::TextureFormat::BC2RGBAUnorm: 302 return DXGI_FORMAT_BC2_UNORM; 303 case wgpu::TextureFormat::BC2RGBAUnormSrgb: 304 return DXGI_FORMAT_BC2_UNORM_SRGB; 305 case wgpu::TextureFormat::BC3RGBAUnorm: 306 return DXGI_FORMAT_BC3_UNORM; 307 case wgpu::TextureFormat::BC3RGBAUnormSrgb: 308 return DXGI_FORMAT_BC3_UNORM_SRGB; 309 case wgpu::TextureFormat::BC4RSnorm: 310 return DXGI_FORMAT_BC4_SNORM; 311 case wgpu::TextureFormat::BC4RUnorm: 312 return DXGI_FORMAT_BC4_UNORM; 313 case wgpu::TextureFormat::BC5RGSnorm: 314 return DXGI_FORMAT_BC5_SNORM; 315 case wgpu::TextureFormat::BC5RGUnorm: 316 return DXGI_FORMAT_BC5_UNORM; 317 case wgpu::TextureFormat::BC6HRGBFloat: 318 return DXGI_FORMAT_BC6H_SF16; 319 case wgpu::TextureFormat::BC6HRGBUfloat: 320 return DXGI_FORMAT_BC6H_UF16; 321 case wgpu::TextureFormat::BC7RGBAUnorm: 322 return DXGI_FORMAT_BC7_UNORM; 323 case wgpu::TextureFormat::BC7RGBAUnormSrgb: 324 return DXGI_FORMAT_BC7_UNORM_SRGB; 325 326 case wgpu::TextureFormat::Undefined: 327 UNREACHABLE(); 328 } 329 } 330 ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor * descriptor)331 MaybeError ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor* descriptor) { 332 if (descriptor->dimension != wgpu::TextureDimension::e2D) { 333 return DAWN_VALIDATION_ERROR("Texture must be 2D"); 334 } 335 336 if (descriptor->mipLevelCount != 1) { 337 return DAWN_VALIDATION_ERROR("Mip level count must be 1"); 338 } 339 340 if (descriptor->size.depth != 1) { 341 return DAWN_VALIDATION_ERROR("Depth must be 1"); 342 } 343 344 if (descriptor->sampleCount != 1) { 345 return DAWN_VALIDATION_ERROR("Sample count must be 1"); 346 } 347 348 return {}; 349 } 350 ValidateD3D12TextureCanBeWrapped(ID3D12Resource * d3d12Resource,const TextureDescriptor * dawnDescriptor)351 MaybeError ValidateD3D12TextureCanBeWrapped(ID3D12Resource* d3d12Resource, 352 const TextureDescriptor* dawnDescriptor) { 353 const D3D12_RESOURCE_DESC d3dDescriptor = d3d12Resource->GetDesc(); 354 if ((dawnDescriptor->size.width != d3dDescriptor.Width) || 355 (dawnDescriptor->size.height != d3dDescriptor.Height) || 356 (dawnDescriptor->size.depth != 1)) { 357 return DAWN_VALIDATION_ERROR("D3D12 texture size doesn't match descriptor"); 358 } 359 360 const DXGI_FORMAT dxgiFormatFromDescriptor = D3D12TextureFormat(dawnDescriptor->format); 361 if (dxgiFormatFromDescriptor != d3dDescriptor.Format) { 362 return DAWN_VALIDATION_ERROR( 363 "D3D12 texture format must be compatible with descriptor format."); 364 } 365 366 if (d3dDescriptor.MipLevels != 1) { 367 return DAWN_VALIDATION_ERROR("D3D12 texture number of miplevels must be 1."); 368 } 369 370 if (d3dDescriptor.DepthOrArraySize != 1) { 371 return DAWN_VALIDATION_ERROR("D3D12 texture array size must be 1."); 372 } 373 374 // Shared textures cannot be multi-sample so no need to check those. 375 ASSERT(d3dDescriptor.SampleDesc.Count == 1); 376 ASSERT(d3dDescriptor.SampleDesc.Quality == 0); 377 378 return {}; 379 } 380 Create(Device * device,const TextureDescriptor * descriptor)381 ResultOrError<Ref<TextureBase>> Texture::Create(Device* device, 382 const TextureDescriptor* descriptor) { 383 Ref<Texture> dawnTexture = 384 AcquireRef(new Texture(device, descriptor, TextureState::OwnedInternal)); 385 DAWN_TRY(dawnTexture->InitializeAsInternalTexture()); 386 return std::move(dawnTexture); 387 } 388 Create(Device * device,const ExternalImageDescriptor * descriptor,HANDLE sharedHandle,ExternalMutexSerial acquireMutexKey,bool isSwapChainTexture)389 ResultOrError<Ref<TextureBase>> Texture::Create(Device* device, 390 const ExternalImageDescriptor* descriptor, 391 HANDLE sharedHandle, 392 ExternalMutexSerial acquireMutexKey, 393 bool isSwapChainTexture) { 394 const TextureDescriptor* textureDescriptor = 395 reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor); 396 397 Ref<Texture> dawnTexture = 398 AcquireRef(new Texture(device, textureDescriptor, TextureState::OwnedExternal)); 399 DAWN_TRY(dawnTexture->InitializeAsExternalTexture(textureDescriptor, sharedHandle, 400 acquireMutexKey, isSwapChainTexture)); 401 dawnTexture->SetIsSubresourceContentInitialized(descriptor->isInitialized, 402 dawnTexture->GetAllSubresources()); 403 return std::move(dawnTexture); 404 } 405 InitializeAsExternalTexture(const TextureDescriptor * descriptor,HANDLE sharedHandle,ExternalMutexSerial acquireMutexKey,bool isSwapChainTexture)406 MaybeError Texture::InitializeAsExternalTexture(const TextureDescriptor* descriptor, 407 HANDLE sharedHandle, 408 ExternalMutexSerial acquireMutexKey, 409 bool isSwapChainTexture) { 410 Device* dawnDevice = ToBackend(GetDevice()); 411 DAWN_TRY(ValidateTextureDescriptor(dawnDevice, descriptor)); 412 DAWN_TRY(ValidateTextureDescriptorCanBeWrapped(descriptor)); 413 414 ComPtr<ID3D12Resource> d3d12Resource; 415 DAWN_TRY(CheckHRESULT(dawnDevice->GetD3D12Device()->OpenSharedHandle( 416 sharedHandle, IID_PPV_ARGS(&d3d12Resource)), 417 "D3D12 opening shared handle")); 418 419 DAWN_TRY(ValidateD3D12TextureCanBeWrapped(d3d12Resource.Get(), descriptor)); 420 421 ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex; 422 DAWN_TRY_ASSIGN(dxgiKeyedMutex, 423 dawnDevice->CreateKeyedMutexForTexture(d3d12Resource.Get())); 424 425 DAWN_TRY(CheckHRESULT(dxgiKeyedMutex->AcquireSync(uint64_t(acquireMutexKey), INFINITE), 426 "D3D12 acquiring shared mutex")); 427 428 mAcquireMutexKey = acquireMutexKey; 429 mDxgiKeyedMutex = std::move(dxgiKeyedMutex); 430 mSwapChainTexture = isSwapChainTexture; 431 432 AllocationInfo info; 433 info.mMethod = AllocationMethod::kExternal; 434 // When creating the ResourceHeapAllocation, the resource heap is set to nullptr because the 435 // texture is owned externally. The texture's owning entity must remain responsible for 436 // memory management. 437 mResourceAllocation = {info, 0, std::move(d3d12Resource), nullptr}; 438 439 return {}; 440 } 441 InitializeAsInternalTexture()442 MaybeError Texture::InitializeAsInternalTexture() { 443 D3D12_RESOURCE_DESC resourceDescriptor; 444 resourceDescriptor.Dimension = D3D12TextureDimension(GetDimension()); 445 resourceDescriptor.Alignment = 0; 446 447 const Extent3D& size = GetSize(); 448 resourceDescriptor.Width = size.width; 449 resourceDescriptor.Height = size.height; 450 resourceDescriptor.DepthOrArraySize = size.depth; 451 452 // This will need to be much more nuanced when WebGPU has 453 // texture view compatibility rules. 454 const bool needsTypelessFormat = 455 GetFormat().HasDepthOrStencil() && (GetUsage() & wgpu::TextureUsage::Sampled) != 0; 456 457 DXGI_FORMAT dxgiFormat = needsTypelessFormat 458 ? D3D12TypelessTextureFormat(GetFormat().format) 459 : D3D12TextureFormat(GetFormat().format); 460 461 resourceDescriptor.MipLevels = static_cast<UINT16>(GetNumMipLevels()); 462 resourceDescriptor.Format = dxgiFormat; 463 resourceDescriptor.SampleDesc.Count = GetSampleCount(); 464 // TODO(bryan.bernhart@intel.com): investigate how to specify standard MSAA sample pattern. 465 resourceDescriptor.SampleDesc.Quality = 0; 466 resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; 467 resourceDescriptor.Flags = 468 D3D12ResourceFlags(GetUsage(), GetFormat(), IsMultisampledTexture()); 469 470 DAWN_TRY_ASSIGN(mResourceAllocation, 471 ToBackend(GetDevice()) 472 ->AllocateMemory(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor, 473 D3D12_RESOURCE_STATE_COMMON)); 474 475 Device* device = ToBackend(GetDevice()); 476 477 if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) { 478 CommandRecordingContext* commandContext; 479 DAWN_TRY_ASSIGN(commandContext, device->GetPendingCommandContext()); 480 481 DAWN_TRY(ClearTexture(commandContext, GetAllSubresources(), 482 TextureBase::ClearValue::NonZero)); 483 } 484 485 return {}; 486 } 487 Texture(Device * device,const TextureDescriptor * descriptor,TextureState state)488 Texture::Texture(Device* device, const TextureDescriptor* descriptor, TextureState state) 489 : TextureBase(device, descriptor, state), 490 mSubresourceStateAndDecay( 491 GetSubresourceCount(), 492 {D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_COMMON, kMaxExecutionSerial, false}) { 493 } 494 Texture(Device * device,const TextureDescriptor * descriptor,ComPtr<ID3D12Resource> nativeTexture)495 Texture::Texture(Device* device, 496 const TextureDescriptor* descriptor, 497 ComPtr<ID3D12Resource> nativeTexture) 498 : Texture(device, descriptor, TextureState::OwnedExternal) { 499 AllocationInfo info; 500 info.mMethod = AllocationMethod::kExternal; 501 // When creating the ResourceHeapAllocation, the resource heap is set to nullptr because the 502 // texture is owned externally. The texture's owning entity must remain responsible for 503 // memory management. 504 mResourceAllocation = {info, 0, std::move(nativeTexture), nullptr}; 505 506 SetIsSubresourceContentInitialized(true, GetAllSubresources()); 507 } 508 ~Texture()509 Texture::~Texture() { 510 DestroyInternal(); 511 } 512 DestroyImpl()513 void Texture::DestroyImpl() { 514 Device* device = ToBackend(GetDevice()); 515 516 // In PIX's D3D12-only mode, there is no way to determine frame boundaries 517 // for WebGPU since Dawn does not manage DXGI swap chains. Without assistance, 518 // PIX will wait forever for a present that never happens. 519 // If we know we're dealing with a swapbuffer texture, inform PIX we've 520 // "presented" the texture so it can determine frame boundaries and use its 521 // contents for the UI. 522 if (mSwapChainTexture) { 523 ID3D12SharingContract* d3dSharingContract = device->GetSharingContract(); 524 if (d3dSharingContract != nullptr) { 525 d3dSharingContract->Present(mResourceAllocation.GetD3D12Resource(), 0, 0); 526 } 527 } 528 529 device->DeallocateMemory(mResourceAllocation); 530 531 if (mDxgiKeyedMutex != nullptr) { 532 mDxgiKeyedMutex->ReleaseSync(uint64_t(mAcquireMutexKey) + 1); 533 device->ReleaseKeyedMutexForTexture(std::move(mDxgiKeyedMutex)); 534 } 535 } 536 GetD3D12Format() const537 DXGI_FORMAT Texture::GetD3D12Format() const { 538 return D3D12TextureFormat(GetFormat().format); 539 } 540 GetD3D12Resource() const541 ID3D12Resource* Texture::GetD3D12Resource() const { 542 return mResourceAllocation.GetD3D12Resource(); 543 } 544 GetD3D12CopyableSubresourceFormat(Aspect aspect) const545 DXGI_FORMAT Texture::GetD3D12CopyableSubresourceFormat(Aspect aspect) const { 546 ASSERT(GetFormat().aspects & aspect); 547 548 switch (GetFormat().format) { 549 case wgpu::TextureFormat::Depth24PlusStencil8: 550 switch (aspect) { 551 case Aspect::Depth: 552 return DXGI_FORMAT_R32_FLOAT; 553 case Aspect::Stencil: 554 return DXGI_FORMAT_R8_UINT; 555 default: 556 UNREACHABLE(); 557 } 558 default: 559 ASSERT(HasOneBit(GetFormat().aspects)); 560 return GetD3D12Format(); 561 } 562 } 563 TrackUsageAndTransitionNow(CommandRecordingContext * commandContext,wgpu::TextureUsage usage,const SubresourceRange & range)564 void Texture::TrackUsageAndTransitionNow(CommandRecordingContext* commandContext, 565 wgpu::TextureUsage usage, 566 const SubresourceRange& range) { 567 TrackUsageAndTransitionNow(commandContext, D3D12TextureUsage(usage, GetFormat()), range); 568 } 569 TrackAllUsageAndTransitionNow(CommandRecordingContext * commandContext,wgpu::TextureUsage usage)570 void Texture::TrackAllUsageAndTransitionNow(CommandRecordingContext* commandContext, 571 wgpu::TextureUsage usage) { 572 TrackUsageAndTransitionNow(commandContext, D3D12TextureUsage(usage, GetFormat()), 573 GetAllSubresources()); 574 } 575 TrackAllUsageAndTransitionNow(CommandRecordingContext * commandContext,D3D12_RESOURCE_STATES newState)576 void Texture::TrackAllUsageAndTransitionNow(CommandRecordingContext* commandContext, 577 D3D12_RESOURCE_STATES newState) { 578 TrackUsageAndTransitionNow(commandContext, newState, GetAllSubresources()); 579 } 580 TrackUsageAndTransitionNow(CommandRecordingContext * commandContext,D3D12_RESOURCE_STATES newState,const SubresourceRange & range)581 void Texture::TrackUsageAndTransitionNow(CommandRecordingContext* commandContext, 582 D3D12_RESOURCE_STATES newState, 583 const SubresourceRange& range) { 584 if (mResourceAllocation.GetInfo().mMethod != AllocationMethod::kExternal) { 585 // Track the underlying heap to ensure residency. 586 Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap()); 587 commandContext->TrackHeapUsage(heap, GetDevice()->GetPendingCommandSerial()); 588 } 589 590 std::vector<D3D12_RESOURCE_BARRIER> barriers; 591 592 // TODO(enga): Consider adding a Count helper. 593 uint32_t aspectCount = 0; 594 for (Aspect aspect : IterateEnumMask(range.aspects)) { 595 aspectCount++; 596 DAWN_UNUSED(aspect); 597 } 598 599 barriers.reserve(range.levelCount * range.layerCount * aspectCount); 600 601 TransitionUsageAndGetResourceBarrier(commandContext, &barriers, newState, range); 602 if (barriers.size()) { 603 commandContext->GetCommandList()->ResourceBarrier(barriers.size(), barriers.data()); 604 } 605 } 606 TransitionSingleOrAllSubresources(std::vector<D3D12_RESOURCE_BARRIER> * barriers,uint32_t index,D3D12_RESOURCE_STATES newState,ExecutionSerial pendingCommandSerial,bool allSubresources)607 void Texture::TransitionSingleOrAllSubresources(std::vector<D3D12_RESOURCE_BARRIER>* barriers, 608 uint32_t index, 609 D3D12_RESOURCE_STATES newState, 610 ExecutionSerial pendingCommandSerial, 611 bool allSubresources) { 612 StateAndDecay* state = &mSubresourceStateAndDecay[index]; 613 // Reuse the subresource(s) directly and avoid transition when it isn't needed, and 614 // return false. 615 // TODO(cwallez@chromium.org): Need some form of UAV barriers at some point. 616 if (state->lastState == newState) { 617 return; 618 } 619 620 D3D12_RESOURCE_STATES lastState = state->lastState; 621 622 // The COMMON state represents a state where no write operations can be pending, and 623 // where all pixels are uncompressed. This makes it possible to transition to and 624 // from some states without synchronization (i.e. without an explicit 625 // ResourceBarrier call). Textures can be implicitly promoted to 1) a single write 626 // state, or 2) multiple read states. Textures will implicitly decay to the COMMON 627 // state when all of the following are true: 1) the texture is accessed on a command 628 // list, 2) the ExecuteCommandLists call that uses that command list has ended, and 629 // 3) the texture was promoted implicitly to a read-only state and is still in that 630 // state. 631 // https://docs.microsoft.com/en-us/windows/desktop/direct3d12/using-resource-barriers-to-synchronize-resource-states-in-direct3d-12#implicit-state-transitions 632 633 // To track implicit decays, we must record the pending serial on which that 634 // transition will occur. When that texture is used again, the previously recorded 635 // serial must be compared to the last completed serial to determine if the texture 636 // has implicity decayed to the common state. 637 if (state->isValidToDecay && pendingCommandSerial > state->lastDecaySerial) { 638 lastState = D3D12_RESOURCE_STATE_COMMON; 639 } 640 641 // Update the tracked state. 642 state->lastState = newState; 643 644 // Destination states that qualify for an implicit promotion for a 645 // non-simultaneous-access texture: NON_PIXEL_SHADER_RESOURCE, 646 // PIXEL_SHADER_RESOURCE, COPY_SRC, COPY_DEST. 647 { 648 static constexpr D3D12_RESOURCE_STATES kD3D12PromotableReadOnlyStates = 649 D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | 650 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; 651 652 if (lastState == D3D12_RESOURCE_STATE_COMMON) { 653 if (IsSubset(newState, kD3D12PromotableReadOnlyStates)) { 654 // Implicit texture state decays can only occur when the texture was implicitly 655 // transitioned to a read-only state. isValidToDecay is needed to differentiate 656 // between resources that were implictly or explicitly transitioned to a 657 // read-only state. 658 state->isValidToDecay = true; 659 state->lastDecaySerial = pendingCommandSerial; 660 return; 661 } else if (newState == D3D12_RESOURCE_STATE_COPY_DEST) { 662 state->isValidToDecay = false; 663 return; 664 } 665 } 666 } 667 668 D3D12_RESOURCE_BARRIER barrier; 669 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; 670 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; 671 barrier.Transition.pResource = GetD3D12Resource(); 672 barrier.Transition.StateBefore = lastState; 673 barrier.Transition.StateAfter = newState; 674 barrier.Transition.Subresource = 675 allSubresources ? D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES : index; 676 barriers->push_back(barrier); 677 678 state->isValidToDecay = false; 679 } 680 HandleTransitionSpecialCases(CommandRecordingContext * commandContext)681 void Texture::HandleTransitionSpecialCases(CommandRecordingContext* commandContext) { 682 // Textures with keyed mutexes can be written from other graphics queues. Hence, they 683 // must be acquired before command list submission to ensure work from the other queues 684 // has finished. See Device::ExecuteCommandContext. 685 if (mDxgiKeyedMutex != nullptr) { 686 commandContext->AddToSharedTextureList(this); 687 } 688 } 689 TransitionUsageAndGetResourceBarrier(CommandRecordingContext * commandContext,std::vector<D3D12_RESOURCE_BARRIER> * barrier,wgpu::TextureUsage usage,const SubresourceRange & range)690 void Texture::TransitionUsageAndGetResourceBarrier(CommandRecordingContext* commandContext, 691 std::vector<D3D12_RESOURCE_BARRIER>* barrier, 692 wgpu::TextureUsage usage, 693 const SubresourceRange& range) { 694 TransitionUsageAndGetResourceBarrier(commandContext, barrier, 695 D3D12TextureUsage(usage, GetFormat()), range); 696 } 697 TransitionUsageAndGetResourceBarrier(CommandRecordingContext * commandContext,std::vector<D3D12_RESOURCE_BARRIER> * barriers,D3D12_RESOURCE_STATES newState,const SubresourceRange & range)698 void Texture::TransitionUsageAndGetResourceBarrier( 699 CommandRecordingContext* commandContext, 700 std::vector<D3D12_RESOURCE_BARRIER>* barriers, 701 D3D12_RESOURCE_STATES newState, 702 const SubresourceRange& range) { 703 HandleTransitionSpecialCases(commandContext); 704 705 const ExecutionSerial pendingCommandSerial = 706 ToBackend(GetDevice())->GetPendingCommandSerial(); 707 708 // This transitions assume it is a 2D texture 709 ASSERT(GetDimension() == wgpu::TextureDimension::e2D); 710 711 // If the usages transitions can cover all subresources, and old usages of all subresources 712 // are the same, then we can use one barrier to do state transition for all subresources. 713 // Note that if the texture has only one mip level and one array slice, it will fall into 714 // this category. 715 bool areAllSubresourcesCovered = (range.levelCount == GetNumMipLevels() && // 716 range.layerCount == GetArrayLayers() && // 717 range.aspects == GetFormat().aspects); 718 if (mSameLastUsagesAcrossSubresources && areAllSubresourcesCovered) { 719 TransitionSingleOrAllSubresources(barriers, 0, newState, pendingCommandSerial, true); 720 721 // TODO(yunchao.he@intel.com): compress and decompress if all subresources have the 722 // same states. We may need to retain mSubresourceStateAndDecay[0] only. 723 for (uint32_t i = 1; i < GetSubresourceCount(); ++i) { 724 mSubresourceStateAndDecay[i] = mSubresourceStateAndDecay[0]; 725 } 726 727 return; 728 } 729 for (Aspect aspect : IterateEnumMask(range.aspects)) { 730 for (uint32_t arrayLayer = 0; arrayLayer < range.layerCount; ++arrayLayer) { 731 for (uint32_t mipLevel = 0; mipLevel < range.levelCount; ++mipLevel) { 732 uint32_t index = GetSubresourceIndex(range.baseMipLevel + mipLevel, 733 range.baseArrayLayer + arrayLayer, aspect); 734 735 TransitionSingleOrAllSubresources(barriers, index, newState, 736 pendingCommandSerial, false); 737 } 738 } 739 } 740 mSameLastUsagesAcrossSubresources = areAllSubresourcesCovered; 741 } 742 TrackUsageAndGetResourceBarrierForPass(CommandRecordingContext * commandContext,std::vector<D3D12_RESOURCE_BARRIER> * barriers,const PassTextureUsage & textureUsages)743 void Texture::TrackUsageAndGetResourceBarrierForPass( 744 CommandRecordingContext* commandContext, 745 std::vector<D3D12_RESOURCE_BARRIER>* barriers, 746 const PassTextureUsage& textureUsages) { 747 if (mResourceAllocation.GetInfo().mMethod != AllocationMethod::kExternal) { 748 // Track the underlying heap to ensure residency. 749 Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap()); 750 commandContext->TrackHeapUsage(heap, GetDevice()->GetPendingCommandSerial()); 751 } 752 753 HandleTransitionSpecialCases(commandContext); 754 755 const ExecutionSerial pendingCommandSerial = 756 ToBackend(GetDevice())->GetPendingCommandSerial(); 757 uint32_t subresourceCount = GetSubresourceCount(); 758 ASSERT(textureUsages.subresourceUsages.size() == subresourceCount); 759 // This transitions assume it is a 2D texture 760 ASSERT(GetDimension() == wgpu::TextureDimension::e2D); 761 762 // If new usages of all subresources are the same and old usages of all subresources are 763 // the same too, we can use one barrier to do state transition for all subresources. 764 // Note that if the texture has only one mip level and one array slice, it will fall into 765 // this category. 766 if (textureUsages.sameUsagesAcrossSubresources && mSameLastUsagesAcrossSubresources) { 767 D3D12_RESOURCE_STATES newState = D3D12TextureUsage(textureUsages.usage, GetFormat()); 768 TransitionSingleOrAllSubresources(barriers, 0, newState, pendingCommandSerial, true); 769 770 // TODO(yunchao.he@intel.com): compress and decompress if all subresources have the 771 // same states. We may need to retain mSubresourceStateAndDecay[0] only. 772 for (uint32_t i = 1; i < subresourceCount; ++i) { 773 mSubresourceStateAndDecay[i] = mSubresourceStateAndDecay[0]; 774 } 775 776 return; 777 } 778 779 for (Aspect aspect : IterateEnumMask(GetFormat().aspects)) { 780 for (uint32_t arrayLayer = 0; arrayLayer < GetArrayLayers(); ++arrayLayer) { 781 for (uint32_t mipLevel = 0; mipLevel < GetNumMipLevels(); ++mipLevel) { 782 uint32_t index = GetSubresourceIndex(mipLevel, arrayLayer, aspect); 783 784 // Skip if this subresource is not used during the current pass 785 if (textureUsages.subresourceUsages[index] == wgpu::TextureUsage::None) { 786 continue; 787 } 788 789 D3D12_RESOURCE_STATES newState = 790 D3D12TextureUsage(textureUsages.subresourceUsages[index], GetFormat()); 791 792 TransitionSingleOrAllSubresources(barriers, index, newState, 793 pendingCommandSerial, false); 794 } 795 } 796 } 797 mSameLastUsagesAcrossSubresources = textureUsages.sameUsagesAcrossSubresources; 798 } 799 GetRTVDescriptor(uint32_t mipLevel,uint32_t baseArrayLayer,uint32_t layerCount) const800 D3D12_RENDER_TARGET_VIEW_DESC Texture::GetRTVDescriptor(uint32_t mipLevel, 801 uint32_t baseArrayLayer, 802 uint32_t layerCount) const { 803 ASSERT(GetDimension() == wgpu::TextureDimension::e2D); 804 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; 805 rtvDesc.Format = GetD3D12Format(); 806 if (IsMultisampledTexture()) { 807 ASSERT(GetNumMipLevels() == 1); 808 ASSERT(layerCount == 1); 809 ASSERT(baseArrayLayer == 0); 810 ASSERT(mipLevel == 0); 811 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS; 812 } else { 813 // Currently we always use D3D12_TEX2D_ARRAY_RTV because we cannot specify base array 814 // layer and layer count in D3D12_TEX2D_RTV. For 2D texture views, we treat them as 815 // 1-layer 2D array textures. (Just like how we treat SRVs) 816 // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_rtv 817 // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_array 818 // _rtv 819 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; 820 rtvDesc.Texture2DArray.FirstArraySlice = baseArrayLayer; 821 rtvDesc.Texture2DArray.ArraySize = layerCount; 822 rtvDesc.Texture2DArray.MipSlice = mipLevel; 823 rtvDesc.Texture2DArray.PlaneSlice = 0; 824 } 825 return rtvDesc; 826 } 827 GetDSVDescriptor(uint32_t mipLevel,uint32_t baseArrayLayer,uint32_t layerCount) const828 D3D12_DEPTH_STENCIL_VIEW_DESC Texture::GetDSVDescriptor(uint32_t mipLevel, 829 uint32_t baseArrayLayer, 830 uint32_t layerCount) const { 831 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc; 832 dsvDesc.Format = GetD3D12Format(); 833 dsvDesc.Flags = D3D12_DSV_FLAG_NONE; 834 835 if (IsMultisampledTexture()) { 836 ASSERT(GetNumMipLevels() == 1); 837 ASSERT(layerCount == 1); 838 ASSERT(baseArrayLayer == 0); 839 ASSERT(mipLevel == 0); 840 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS; 841 } else { 842 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY; 843 dsvDesc.Texture2DArray.FirstArraySlice = baseArrayLayer; 844 dsvDesc.Texture2DArray.ArraySize = layerCount; 845 dsvDesc.Texture2DArray.MipSlice = mipLevel; 846 } 847 848 return dsvDesc; 849 } 850 ClearTexture(CommandRecordingContext * commandContext,const SubresourceRange & range,TextureBase::ClearValue clearValue)851 MaybeError Texture::ClearTexture(CommandRecordingContext* commandContext, 852 const SubresourceRange& range, 853 TextureBase::ClearValue clearValue) { 854 // TODO(jiawei.shao@intel.com): initialize the textures in compressed formats with copies. 855 if (GetFormat().isCompressed) { 856 SetIsSubresourceContentInitialized(true, range); 857 return {}; 858 } 859 860 ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList(); 861 862 Device* device = ToBackend(GetDevice()); 863 864 uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1; 865 float fClearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0.f : 1.f; 866 867 if ((GetUsage() & wgpu::TextureUsage::RenderAttachment) != 0) { 868 if (GetFormat().HasDepthOrStencil()) { 869 TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE, range); 870 871 for (uint32_t level = range.baseMipLevel; 872 level < range.baseMipLevel + range.levelCount; ++level) { 873 for (uint32_t layer = range.baseArrayLayer; 874 layer < range.baseArrayLayer + range.layerCount; ++layer) { 875 // Iterate the aspects individually to determine which clear flags to use. 876 D3D12_CLEAR_FLAGS clearFlags = {}; 877 for (Aspect aspect : IterateEnumMask(range.aspects)) { 878 if (clearValue == TextureBase::ClearValue::Zero && 879 IsSubresourceContentInitialized( 880 SubresourceRange::SingleMipAndLayer(level, layer, aspect))) { 881 // Skip lazy clears if already initialized. 882 continue; 883 } 884 885 switch (aspect) { 886 case Aspect::Depth: 887 clearFlags |= D3D12_CLEAR_FLAG_DEPTH; 888 break; 889 case Aspect::Stencil: 890 clearFlags |= D3D12_CLEAR_FLAG_STENCIL; 891 break; 892 default: 893 UNREACHABLE(); 894 } 895 } 896 897 if (clearFlags == 0) { 898 continue; 899 } 900 901 CPUDescriptorHeapAllocation dsvHandle; 902 DAWN_TRY_ASSIGN(dsvHandle, device->GetDepthStencilViewAllocator() 903 ->AllocateTransientCPUDescriptors()); 904 const D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor = 905 dsvHandle.GetBaseDescriptor(); 906 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = GetDSVDescriptor(level, layer, 1); 907 device->GetD3D12Device()->CreateDepthStencilView(GetD3D12Resource(), 908 &dsvDesc, baseDescriptor); 909 910 commandList->ClearDepthStencilView(baseDescriptor, clearFlags, fClearColor, 911 clearColor, 0, nullptr); 912 } 913 } 914 } else { 915 TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_RENDER_TARGET, 916 range); 917 918 const float clearColorRGBA[4] = {fClearColor, fClearColor, fClearColor, 919 fClearColor}; 920 921 ASSERT(range.aspects == Aspect::Color); 922 for (uint32_t level = range.baseMipLevel; 923 level < range.baseMipLevel + range.levelCount; ++level) { 924 for (uint32_t layer = range.baseArrayLayer; 925 layer < range.baseArrayLayer + range.layerCount; ++layer) { 926 if (clearValue == TextureBase::ClearValue::Zero && 927 IsSubresourceContentInitialized( 928 SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) { 929 // Skip lazy clears if already initialized. 930 continue; 931 } 932 933 CPUDescriptorHeapAllocation rtvHeap; 934 DAWN_TRY_ASSIGN(rtvHeap, device->GetRenderTargetViewAllocator() 935 ->AllocateTransientCPUDescriptors()); 936 const D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetBaseDescriptor(); 937 938 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = GetRTVDescriptor(level, layer, 1); 939 device->GetD3D12Device()->CreateRenderTargetView(GetD3D12Resource(), 940 &rtvDesc, rtvHandle); 941 commandList->ClearRenderTargetView(rtvHandle, clearColorRGBA, 0, nullptr); 942 } 943 } 944 } 945 } else { 946 // create temp buffer with clear color to copy to the texture image 947 TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_COPY_DEST, range); 948 949 for (Aspect aspect : IterateEnumMask(range.aspects)) { 950 const TexelBlockInfo& blockInfo = GetFormat().GetAspectInfo(aspect).block; 951 952 uint32_t bytesPerRow = Align((GetWidth() / blockInfo.width) * blockInfo.byteSize, 953 kTextureBytesPerRowAlignment); 954 uint64_t bufferSize64 = bytesPerRow * (GetHeight() / blockInfo.height); 955 if (bufferSize64 > std::numeric_limits<uint32_t>::max()) { 956 return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer."); 957 } 958 uint32_t bufferSize = static_cast<uint32_t>(bufferSize64); 959 960 DynamicUploader* uploader = device->GetDynamicUploader(); 961 UploadHandle uploadHandle; 962 DAWN_TRY_ASSIGN(uploadHandle, 963 uploader->Allocate(bufferSize, device->GetPendingCommandSerial(), 964 blockInfo.byteSize)); 965 memset(uploadHandle.mappedBuffer, clearColor, bufferSize); 966 967 for (uint32_t level = range.baseMipLevel; 968 level < range.baseMipLevel + range.levelCount; ++level) { 969 // compute d3d12 texture copy locations for texture and buffer 970 Extent3D copySize = GetMipLevelVirtualSize(level); 971 972 uint32_t rowsPerImage = GetHeight() / blockInfo.height; 973 Texture2DCopySplit copySplit = ComputeTextureCopySplit( 974 {0, 0, 0}, copySize, blockInfo, uploadHandle.startOffset, bytesPerRow, 975 rowsPerImage); 976 977 for (uint32_t layer = range.baseArrayLayer; 978 layer < range.baseArrayLayer + range.layerCount; ++layer) { 979 if (clearValue == TextureBase::ClearValue::Zero && 980 IsSubresourceContentInitialized( 981 SubresourceRange::SingleMipAndLayer(level, layer, aspect))) { 982 // Skip lazy clears if already initialized. 983 continue; 984 } 985 986 D3D12_TEXTURE_COPY_LOCATION textureLocation = 987 ComputeTextureCopyLocationForTexture(this, level, layer, aspect); 988 for (uint32_t i = 0; i < copySplit.count; ++i) { 989 Texture2DCopySplit::CopyInfo& info = copySplit.copies[i]; 990 991 D3D12_TEXTURE_COPY_LOCATION bufferLocation = 992 ComputeBufferLocationForCopyTextureRegion( 993 this, ToBackend(uploadHandle.stagingBuffer)->GetResource(), 994 info.bufferSize, copySplit.offset, bytesPerRow, aspect); 995 D3D12_BOX sourceRegion = 996 ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize); 997 998 // copy the buffer filled with clear color to the texture 999 commandList->CopyTextureRegion( 1000 &textureLocation, info.textureOffset.x, info.textureOffset.y, 1001 info.textureOffset.z, &bufferLocation, &sourceRegion); 1002 } 1003 } 1004 } 1005 } 1006 } 1007 if (clearValue == TextureBase::ClearValue::Zero) { 1008 SetIsSubresourceContentInitialized(true, range); 1009 GetDevice()->IncrementLazyClearCountForTesting(); 1010 } 1011 return {}; 1012 } 1013 EnsureSubresourceContentInitialized(CommandRecordingContext * commandContext,const SubresourceRange & range)1014 void Texture::EnsureSubresourceContentInitialized(CommandRecordingContext* commandContext, 1015 const SubresourceRange& range) { 1016 if (!ToBackend(GetDevice())->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse)) { 1017 return; 1018 } 1019 if (!IsSubresourceContentInitialized(range)) { 1020 // If subresource has not been initialized, clear it to black as it could contain 1021 // dirty bits from recycled memory 1022 GetDevice()->ConsumedError( 1023 ClearTexture(commandContext, range, TextureBase::ClearValue::Zero)); 1024 } 1025 } 1026 TextureView(TextureBase * texture,const TextureViewDescriptor * descriptor)1027 TextureView::TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor) 1028 : TextureViewBase(texture, descriptor) { 1029 mSrvDesc.Format = D3D12TextureFormat(descriptor->format); 1030 mSrvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; 1031 1032 // TODO(enga): This will need to be much more nuanced when WebGPU has 1033 // texture view compatibility rules. 1034 UINT planeSlice = 0; 1035 if (GetFormat().HasDepthOrStencil()) { 1036 // Configure the SRV descriptor to reinterpret the texture allocated as 1037 // TYPELESS as a single-plane shader-accessible view. 1038 switch (descriptor->format) { 1039 case wgpu::TextureFormat::Depth32Float: 1040 case wgpu::TextureFormat::Depth24Plus: 1041 mSrvDesc.Format = DXGI_FORMAT_R32_FLOAT; 1042 break; 1043 case wgpu::TextureFormat::Depth24PlusStencil8: 1044 switch (descriptor->aspect) { 1045 case wgpu::TextureAspect::DepthOnly: 1046 planeSlice = 0; 1047 mSrvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; 1048 break; 1049 case wgpu::TextureAspect::StencilOnly: 1050 planeSlice = 1; 1051 mSrvDesc.Format = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; 1052 // Stencil is accessed using the .g component in the shader. 1053 // Map it to the zeroth component to match other APIs. 1054 mSrvDesc.Shader4ComponentMapping = 1055 D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( 1056 D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, 1057 D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, 1058 D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, 1059 D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1); 1060 break; 1061 case wgpu::TextureAspect::All: 1062 // A single aspect is not selected. The texture view must not be 1063 // sampled. 1064 mSrvDesc.Format = DXGI_FORMAT_UNKNOWN; 1065 break; 1066 } 1067 break; 1068 default: 1069 UNREACHABLE(); 1070 break; 1071 } 1072 } 1073 1074 // Currently we always use D3D12_TEX2D_ARRAY_SRV because we cannot specify base array layer 1075 // and layer count in D3D12_TEX2D_SRV. For 2D texture views, we treat them as 1-layer 2D 1076 // array textures. 1077 // Multisampled textures may only be one array layer, so we use 1078 // D3D12_SRV_DIMENSION_TEXTURE2DMS. 1079 // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_srv 1080 // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_array_srv 1081 // TODO(jiawei.shao@intel.com): support more texture view dimensions. 1082 if (GetTexture()->IsMultisampledTexture()) { 1083 switch (descriptor->dimension) { 1084 case wgpu::TextureViewDimension::e2DArray: 1085 ASSERT(texture->GetArrayLayers() == 1); 1086 DAWN_FALLTHROUGH; 1087 case wgpu::TextureViewDimension::e2D: 1088 ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); 1089 mSrvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS; 1090 break; 1091 1092 default: 1093 UNREACHABLE(); 1094 } 1095 } else { 1096 switch (descriptor->dimension) { 1097 case wgpu::TextureViewDimension::e2D: 1098 case wgpu::TextureViewDimension::e2DArray: 1099 ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); 1100 mSrvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; 1101 mSrvDesc.Texture2DArray.ArraySize = descriptor->arrayLayerCount; 1102 mSrvDesc.Texture2DArray.FirstArraySlice = descriptor->baseArrayLayer; 1103 mSrvDesc.Texture2DArray.MipLevels = descriptor->mipLevelCount; 1104 mSrvDesc.Texture2DArray.MostDetailedMip = descriptor->baseMipLevel; 1105 mSrvDesc.Texture2DArray.PlaneSlice = planeSlice; 1106 mSrvDesc.Texture2DArray.ResourceMinLODClamp = 0; 1107 break; 1108 case wgpu::TextureViewDimension::Cube: 1109 case wgpu::TextureViewDimension::CubeArray: 1110 ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); 1111 ASSERT(descriptor->arrayLayerCount % 6 == 0); 1112 mSrvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; 1113 mSrvDesc.TextureCubeArray.First2DArrayFace = descriptor->baseArrayLayer; 1114 mSrvDesc.TextureCubeArray.NumCubes = descriptor->arrayLayerCount / 6; 1115 mSrvDesc.TextureCubeArray.MostDetailedMip = descriptor->baseMipLevel; 1116 mSrvDesc.TextureCubeArray.MipLevels = descriptor->mipLevelCount; 1117 mSrvDesc.TextureCubeArray.ResourceMinLODClamp = 0; 1118 break; 1119 1120 case wgpu::TextureViewDimension::e1D: 1121 case wgpu::TextureViewDimension::e3D: 1122 case wgpu::TextureViewDimension::Undefined: 1123 UNREACHABLE(); 1124 } 1125 } 1126 } 1127 GetD3D12Format() const1128 DXGI_FORMAT TextureView::GetD3D12Format() const { 1129 return D3D12TextureFormat(GetFormat().format); 1130 } 1131 GetSRVDescriptor() const1132 const D3D12_SHADER_RESOURCE_VIEW_DESC& TextureView::GetSRVDescriptor() const { 1133 ASSERT(mSrvDesc.Format != DXGI_FORMAT_UNKNOWN); 1134 return mSrvDesc; 1135 } 1136 GetRTVDescriptor() const1137 D3D12_RENDER_TARGET_VIEW_DESC TextureView::GetRTVDescriptor() const { 1138 return ToBackend(GetTexture()) 1139 ->GetRTVDescriptor(GetBaseMipLevel(), GetBaseArrayLayer(), GetLayerCount()); 1140 } 1141 GetDSVDescriptor() const1142 D3D12_DEPTH_STENCIL_VIEW_DESC TextureView::GetDSVDescriptor() const { 1143 ASSERT(GetLevelCount() == 1); 1144 return ToBackend(GetTexture()) 1145 ->GetDSVDescriptor(GetBaseMipLevel(), GetBaseArrayLayer(), GetLayerCount()); 1146 } 1147 GetUAVDescriptor() const1148 D3D12_UNORDERED_ACCESS_VIEW_DESC TextureView::GetUAVDescriptor() const { 1149 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc; 1150 uavDesc.Format = GetD3D12Format(); 1151 1152 ASSERT(!GetTexture()->IsMultisampledTexture()); 1153 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY; 1154 uavDesc.Texture2DArray.FirstArraySlice = GetBaseArrayLayer(); 1155 uavDesc.Texture2DArray.ArraySize = GetLayerCount(); 1156 uavDesc.Texture2DArray.MipSlice = GetBaseMipLevel(); 1157 uavDesc.Texture2DArray.PlaneSlice = 0; 1158 return uavDesc; 1159 } 1160 1161 }} // namespace dawn_native::d3d12 1162