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/D3D11on12Util.h" 25 #include "dawn_native/d3d12/D3D12Error.h" 26 #include "dawn_native/d3d12/DeviceD3D12.h" 27 #include "dawn_native/d3d12/HeapD3D12.h" 28 #include "dawn_native/d3d12/ResourceAllocatorManagerD3D12.h" 29 #include "dawn_native/d3d12/StagingBufferD3D12.h" 30 #include "dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h" 31 #include "dawn_native/d3d12/TextureCopySplitter.h" 32 #include "dawn_native/d3d12/UtilsD3D12.h" 33 34 namespace dawn_native { namespace d3d12 { 35 36 namespace { D3D12TextureUsage(wgpu::TextureUsage usage,const Format & format)37 D3D12_RESOURCE_STATES D3D12TextureUsage(wgpu::TextureUsage usage, const Format& format) { 38 D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_COMMON; 39 40 if (usage & kPresentTextureUsage) { 41 // The present usage is only used internally by the swapchain and is never used in 42 // combination with other usages. 43 ASSERT(usage == kPresentTextureUsage); 44 return D3D12_RESOURCE_STATE_PRESENT; 45 } 46 47 if (usage & wgpu::TextureUsage::CopySrc) { 48 resourceState |= D3D12_RESOURCE_STATE_COPY_SOURCE; 49 } 50 if (usage & wgpu::TextureUsage::CopyDst) { 51 resourceState |= D3D12_RESOURCE_STATE_COPY_DEST; 52 } 53 if (usage & (wgpu::TextureUsage::TextureBinding)) { 54 resourceState |= (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | 55 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); 56 } 57 if (usage & wgpu::TextureUsage::StorageBinding) { 58 resourceState |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS; 59 } 60 if (usage & wgpu::TextureUsage::RenderAttachment) { 61 if (format.HasDepthOrStencil()) { 62 resourceState |= D3D12_RESOURCE_STATE_DEPTH_WRITE; 63 } else { 64 resourceState |= D3D12_RESOURCE_STATE_RENDER_TARGET; 65 } 66 } 67 68 if (usage & kReadOnlyRenderAttachment) { 69 // There is no STENCIL_READ state. Readonly for stencil is bundled with DEPTH_READ. 70 resourceState |= D3D12_RESOURCE_STATE_DEPTH_READ; 71 } 72 73 return resourceState; 74 } 75 D3D12ResourceFlags(wgpu::TextureUsage usage,const Format & format,bool isMultisampledTexture)76 D3D12_RESOURCE_FLAGS D3D12ResourceFlags(wgpu::TextureUsage usage, 77 const Format& format, 78 bool isMultisampledTexture) { 79 D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE; 80 81 if (usage & wgpu::TextureUsage::StorageBinding) { 82 flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; 83 } 84 85 // A multisampled resource must have either D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET or 86 // D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL set in D3D12_RESOURCE_DESC::Flags. 87 // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_resource_desc 88 if ((usage & wgpu::TextureUsage::RenderAttachment) != 0 || isMultisampledTexture) { 89 if (format.HasDepthOrStencil()) { 90 flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; 91 } else { 92 flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; 93 } 94 } 95 96 ASSERT(!(flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) || 97 flags == D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); 98 return flags; 99 } 100 D3D12TextureDimension(wgpu::TextureDimension dimension)101 D3D12_RESOURCE_DIMENSION D3D12TextureDimension(wgpu::TextureDimension dimension) { 102 switch (dimension) { 103 case wgpu::TextureDimension::e2D: 104 return D3D12_RESOURCE_DIMENSION_TEXTURE2D; 105 case wgpu::TextureDimension::e3D: 106 return D3D12_RESOURCE_DIMENSION_TEXTURE3D; 107 108 case wgpu::TextureDimension::e1D: 109 UNREACHABLE(); 110 } 111 } 112 D3D12TypelessTextureFormat(wgpu::TextureFormat format)113 DXGI_FORMAT D3D12TypelessTextureFormat(wgpu::TextureFormat format) { 114 switch (format) { 115 case wgpu::TextureFormat::R8Unorm: 116 case wgpu::TextureFormat::R8Snorm: 117 case wgpu::TextureFormat::R8Uint: 118 case wgpu::TextureFormat::R8Sint: 119 return DXGI_FORMAT_R8_TYPELESS; 120 121 case wgpu::TextureFormat::R16Uint: 122 case wgpu::TextureFormat::R16Sint: 123 case wgpu::TextureFormat::R16Float: 124 case wgpu::TextureFormat::Depth16Unorm: 125 return DXGI_FORMAT_R16_TYPELESS; 126 127 case wgpu::TextureFormat::RG8Unorm: 128 case wgpu::TextureFormat::RG8Snorm: 129 case wgpu::TextureFormat::RG8Uint: 130 case wgpu::TextureFormat::RG8Sint: 131 return DXGI_FORMAT_R8G8_TYPELESS; 132 133 case wgpu::TextureFormat::R32Uint: 134 case wgpu::TextureFormat::R32Sint: 135 case wgpu::TextureFormat::R32Float: 136 return DXGI_FORMAT_R32_TYPELESS; 137 138 case wgpu::TextureFormat::RG16Uint: 139 case wgpu::TextureFormat::RG16Sint: 140 case wgpu::TextureFormat::RG16Float: 141 return DXGI_FORMAT_R16G16_TYPELESS; 142 143 case wgpu::TextureFormat::RGBA8Unorm: 144 case wgpu::TextureFormat::RGBA8UnormSrgb: 145 case wgpu::TextureFormat::RGBA8Snorm: 146 case wgpu::TextureFormat::RGBA8Uint: 147 case wgpu::TextureFormat::RGBA8Sint: 148 return DXGI_FORMAT_R8G8B8A8_TYPELESS; 149 150 case wgpu::TextureFormat::BGRA8Unorm: 151 case wgpu::TextureFormat::BGRA8UnormSrgb: 152 return DXGI_FORMAT_B8G8R8A8_TYPELESS; 153 154 case wgpu::TextureFormat::RGB10A2Unorm: 155 return DXGI_FORMAT_R10G10B10A2_TYPELESS; 156 157 case wgpu::TextureFormat::RG11B10Ufloat: 158 return DXGI_FORMAT_R11G11B10_FLOAT; 159 case wgpu::TextureFormat::RGB9E5Ufloat: 160 return DXGI_FORMAT_R9G9B9E5_SHAREDEXP; 161 162 case wgpu::TextureFormat::RG32Uint: 163 case wgpu::TextureFormat::RG32Sint: 164 case wgpu::TextureFormat::RG32Float: 165 return DXGI_FORMAT_R32G32_TYPELESS; 166 167 case wgpu::TextureFormat::RGBA16Uint: 168 case wgpu::TextureFormat::RGBA16Sint: 169 case wgpu::TextureFormat::RGBA16Float: 170 return DXGI_FORMAT_R16G16B16A16_TYPELESS; 171 172 case wgpu::TextureFormat::RGBA32Uint: 173 case wgpu::TextureFormat::RGBA32Sint: 174 case wgpu::TextureFormat::RGBA32Float: 175 return DXGI_FORMAT_R32G32B32A32_TYPELESS; 176 177 case wgpu::TextureFormat::Depth32Float: 178 case wgpu::TextureFormat::Depth24Plus: 179 return DXGI_FORMAT_R32_TYPELESS; 180 181 case wgpu::TextureFormat::Depth24PlusStencil8: 182 return DXGI_FORMAT_R32G8X24_TYPELESS; 183 184 case wgpu::TextureFormat::BC1RGBAUnorm: 185 case wgpu::TextureFormat::BC1RGBAUnormSrgb: 186 return DXGI_FORMAT_BC1_TYPELESS; 187 188 case wgpu::TextureFormat::BC2RGBAUnorm: 189 case wgpu::TextureFormat::BC2RGBAUnormSrgb: 190 return DXGI_FORMAT_BC2_TYPELESS; 191 192 case wgpu::TextureFormat::BC3RGBAUnorm: 193 case wgpu::TextureFormat::BC3RGBAUnormSrgb: 194 return DXGI_FORMAT_BC3_TYPELESS; 195 196 case wgpu::TextureFormat::BC4RSnorm: 197 case wgpu::TextureFormat::BC4RUnorm: 198 return DXGI_FORMAT_BC4_TYPELESS; 199 200 case wgpu::TextureFormat::BC5RGSnorm: 201 case wgpu::TextureFormat::BC5RGUnorm: 202 return DXGI_FORMAT_BC5_TYPELESS; 203 204 case wgpu::TextureFormat::BC6HRGBFloat: 205 case wgpu::TextureFormat::BC6HRGBUfloat: 206 return DXGI_FORMAT_BC6H_TYPELESS; 207 208 case wgpu::TextureFormat::BC7RGBAUnorm: 209 case wgpu::TextureFormat::BC7RGBAUnormSrgb: 210 return DXGI_FORMAT_BC7_TYPELESS; 211 212 case wgpu::TextureFormat::ETC2RGB8Unorm: 213 case wgpu::TextureFormat::ETC2RGB8UnormSrgb: 214 case wgpu::TextureFormat::ETC2RGB8A1Unorm: 215 case wgpu::TextureFormat::ETC2RGB8A1UnormSrgb: 216 case wgpu::TextureFormat::ETC2RGBA8Unorm: 217 case wgpu::TextureFormat::ETC2RGBA8UnormSrgb: 218 case wgpu::TextureFormat::EACR11Unorm: 219 case wgpu::TextureFormat::EACR11Snorm: 220 case wgpu::TextureFormat::EACRG11Unorm: 221 case wgpu::TextureFormat::EACRG11Snorm: 222 223 case wgpu::TextureFormat::ASTC4x4Unorm: 224 case wgpu::TextureFormat::ASTC4x4UnormSrgb: 225 case wgpu::TextureFormat::ASTC5x4Unorm: 226 case wgpu::TextureFormat::ASTC5x4UnormSrgb: 227 case wgpu::TextureFormat::ASTC5x5Unorm: 228 case wgpu::TextureFormat::ASTC5x5UnormSrgb: 229 case wgpu::TextureFormat::ASTC6x5Unorm: 230 case wgpu::TextureFormat::ASTC6x5UnormSrgb: 231 case wgpu::TextureFormat::ASTC6x6Unorm: 232 case wgpu::TextureFormat::ASTC6x6UnormSrgb: 233 case wgpu::TextureFormat::ASTC8x5Unorm: 234 case wgpu::TextureFormat::ASTC8x5UnormSrgb: 235 case wgpu::TextureFormat::ASTC8x6Unorm: 236 case wgpu::TextureFormat::ASTC8x6UnormSrgb: 237 case wgpu::TextureFormat::ASTC8x8Unorm: 238 case wgpu::TextureFormat::ASTC8x8UnormSrgb: 239 case wgpu::TextureFormat::ASTC10x5Unorm: 240 case wgpu::TextureFormat::ASTC10x5UnormSrgb: 241 case wgpu::TextureFormat::ASTC10x6Unorm: 242 case wgpu::TextureFormat::ASTC10x6UnormSrgb: 243 case wgpu::TextureFormat::ASTC10x8Unorm: 244 case wgpu::TextureFormat::ASTC10x8UnormSrgb: 245 case wgpu::TextureFormat::ASTC10x10Unorm: 246 case wgpu::TextureFormat::ASTC10x10UnormSrgb: 247 case wgpu::TextureFormat::ASTC12x10Unorm: 248 case wgpu::TextureFormat::ASTC12x10UnormSrgb: 249 case wgpu::TextureFormat::ASTC12x12Unorm: 250 case wgpu::TextureFormat::ASTC12x12UnormSrgb: 251 252 case wgpu::TextureFormat::R8BG8Biplanar420Unorm: 253 // TODO(dawn:666): implement stencil8 254 case wgpu::TextureFormat::Stencil8: 255 // TODO(dawn:690): implement depth24unorm-stencil8 256 case wgpu::TextureFormat::Depth24UnormStencil8: 257 // TODO(dawn:690): implement depth32float-stencil8 258 case wgpu::TextureFormat::Depth32FloatStencil8: 259 case wgpu::TextureFormat::Undefined: 260 UNREACHABLE(); 261 } 262 } 263 264 } // namespace 265 D3D12TextureFormat(wgpu::TextureFormat format)266 DXGI_FORMAT D3D12TextureFormat(wgpu::TextureFormat format) { 267 switch (format) { 268 case wgpu::TextureFormat::R8Unorm: 269 return DXGI_FORMAT_R8_UNORM; 270 case wgpu::TextureFormat::R8Snorm: 271 return DXGI_FORMAT_R8_SNORM; 272 case wgpu::TextureFormat::R8Uint: 273 return DXGI_FORMAT_R8_UINT; 274 case wgpu::TextureFormat::R8Sint: 275 return DXGI_FORMAT_R8_SINT; 276 277 case wgpu::TextureFormat::R16Uint: 278 return DXGI_FORMAT_R16_UINT; 279 case wgpu::TextureFormat::R16Sint: 280 return DXGI_FORMAT_R16_SINT; 281 case wgpu::TextureFormat::R16Float: 282 return DXGI_FORMAT_R16_FLOAT; 283 case wgpu::TextureFormat::RG8Unorm: 284 return DXGI_FORMAT_R8G8_UNORM; 285 case wgpu::TextureFormat::RG8Snorm: 286 return DXGI_FORMAT_R8G8_SNORM; 287 case wgpu::TextureFormat::RG8Uint: 288 return DXGI_FORMAT_R8G8_UINT; 289 case wgpu::TextureFormat::RG8Sint: 290 return DXGI_FORMAT_R8G8_SINT; 291 292 case wgpu::TextureFormat::R32Uint: 293 return DXGI_FORMAT_R32_UINT; 294 case wgpu::TextureFormat::R32Sint: 295 return DXGI_FORMAT_R32_SINT; 296 case wgpu::TextureFormat::R32Float: 297 return DXGI_FORMAT_R32_FLOAT; 298 case wgpu::TextureFormat::RG16Uint: 299 return DXGI_FORMAT_R16G16_UINT; 300 case wgpu::TextureFormat::RG16Sint: 301 return DXGI_FORMAT_R16G16_SINT; 302 case wgpu::TextureFormat::RG16Float: 303 return DXGI_FORMAT_R16G16_FLOAT; 304 case wgpu::TextureFormat::RGBA8Unorm: 305 return DXGI_FORMAT_R8G8B8A8_UNORM; 306 case wgpu::TextureFormat::RGBA8UnormSrgb: 307 return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; 308 case wgpu::TextureFormat::RGBA8Snorm: 309 return DXGI_FORMAT_R8G8B8A8_SNORM; 310 case wgpu::TextureFormat::RGBA8Uint: 311 return DXGI_FORMAT_R8G8B8A8_UINT; 312 case wgpu::TextureFormat::RGBA8Sint: 313 return DXGI_FORMAT_R8G8B8A8_SINT; 314 case wgpu::TextureFormat::BGRA8Unorm: 315 return DXGI_FORMAT_B8G8R8A8_UNORM; 316 case wgpu::TextureFormat::BGRA8UnormSrgb: 317 return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; 318 case wgpu::TextureFormat::RGB10A2Unorm: 319 return DXGI_FORMAT_R10G10B10A2_UNORM; 320 case wgpu::TextureFormat::RG11B10Ufloat: 321 return DXGI_FORMAT_R11G11B10_FLOAT; 322 case wgpu::TextureFormat::RGB9E5Ufloat: 323 return DXGI_FORMAT_R9G9B9E5_SHAREDEXP; 324 325 case wgpu::TextureFormat::RG32Uint: 326 return DXGI_FORMAT_R32G32_UINT; 327 case wgpu::TextureFormat::RG32Sint: 328 return DXGI_FORMAT_R32G32_SINT; 329 case wgpu::TextureFormat::RG32Float: 330 return DXGI_FORMAT_R32G32_FLOAT; 331 case wgpu::TextureFormat::RGBA16Uint: 332 return DXGI_FORMAT_R16G16B16A16_UINT; 333 case wgpu::TextureFormat::RGBA16Sint: 334 return DXGI_FORMAT_R16G16B16A16_SINT; 335 case wgpu::TextureFormat::RGBA16Float: 336 return DXGI_FORMAT_R16G16B16A16_FLOAT; 337 338 case wgpu::TextureFormat::RGBA32Uint: 339 return DXGI_FORMAT_R32G32B32A32_UINT; 340 case wgpu::TextureFormat::RGBA32Sint: 341 return DXGI_FORMAT_R32G32B32A32_SINT; 342 case wgpu::TextureFormat::RGBA32Float: 343 return DXGI_FORMAT_R32G32B32A32_FLOAT; 344 345 case wgpu::TextureFormat::Depth32Float: 346 return DXGI_FORMAT_D32_FLOAT; 347 case wgpu::TextureFormat::Depth24Plus: 348 return DXGI_FORMAT_D32_FLOAT; 349 case wgpu::TextureFormat::Depth24PlusStencil8: 350 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; 351 case wgpu::TextureFormat::Depth16Unorm: 352 return DXGI_FORMAT_D16_UNORM; 353 354 case wgpu::TextureFormat::BC1RGBAUnorm: 355 return DXGI_FORMAT_BC1_UNORM; 356 case wgpu::TextureFormat::BC1RGBAUnormSrgb: 357 return DXGI_FORMAT_BC1_UNORM_SRGB; 358 case wgpu::TextureFormat::BC2RGBAUnorm: 359 return DXGI_FORMAT_BC2_UNORM; 360 case wgpu::TextureFormat::BC2RGBAUnormSrgb: 361 return DXGI_FORMAT_BC2_UNORM_SRGB; 362 case wgpu::TextureFormat::BC3RGBAUnorm: 363 return DXGI_FORMAT_BC3_UNORM; 364 case wgpu::TextureFormat::BC3RGBAUnormSrgb: 365 return DXGI_FORMAT_BC3_UNORM_SRGB; 366 case wgpu::TextureFormat::BC4RSnorm: 367 return DXGI_FORMAT_BC4_SNORM; 368 case wgpu::TextureFormat::BC4RUnorm: 369 return DXGI_FORMAT_BC4_UNORM; 370 case wgpu::TextureFormat::BC5RGSnorm: 371 return DXGI_FORMAT_BC5_SNORM; 372 case wgpu::TextureFormat::BC5RGUnorm: 373 return DXGI_FORMAT_BC5_UNORM; 374 case wgpu::TextureFormat::BC6HRGBFloat: 375 return DXGI_FORMAT_BC6H_SF16; 376 case wgpu::TextureFormat::BC6HRGBUfloat: 377 return DXGI_FORMAT_BC6H_UF16; 378 case wgpu::TextureFormat::BC7RGBAUnorm: 379 return DXGI_FORMAT_BC7_UNORM; 380 case wgpu::TextureFormat::BC7RGBAUnormSrgb: 381 return DXGI_FORMAT_BC7_UNORM_SRGB; 382 383 case wgpu::TextureFormat::R8BG8Biplanar420Unorm: 384 return DXGI_FORMAT_NV12; 385 386 case wgpu::TextureFormat::ETC2RGB8Unorm: 387 case wgpu::TextureFormat::ETC2RGB8UnormSrgb: 388 case wgpu::TextureFormat::ETC2RGB8A1Unorm: 389 case wgpu::TextureFormat::ETC2RGB8A1UnormSrgb: 390 case wgpu::TextureFormat::ETC2RGBA8Unorm: 391 case wgpu::TextureFormat::ETC2RGBA8UnormSrgb: 392 case wgpu::TextureFormat::EACR11Unorm: 393 case wgpu::TextureFormat::EACR11Snorm: 394 case wgpu::TextureFormat::EACRG11Unorm: 395 case wgpu::TextureFormat::EACRG11Snorm: 396 397 case wgpu::TextureFormat::ASTC4x4Unorm: 398 case wgpu::TextureFormat::ASTC4x4UnormSrgb: 399 case wgpu::TextureFormat::ASTC5x4Unorm: 400 case wgpu::TextureFormat::ASTC5x4UnormSrgb: 401 case wgpu::TextureFormat::ASTC5x5Unorm: 402 case wgpu::TextureFormat::ASTC5x5UnormSrgb: 403 case wgpu::TextureFormat::ASTC6x5Unorm: 404 case wgpu::TextureFormat::ASTC6x5UnormSrgb: 405 case wgpu::TextureFormat::ASTC6x6Unorm: 406 case wgpu::TextureFormat::ASTC6x6UnormSrgb: 407 case wgpu::TextureFormat::ASTC8x5Unorm: 408 case wgpu::TextureFormat::ASTC8x5UnormSrgb: 409 case wgpu::TextureFormat::ASTC8x6Unorm: 410 case wgpu::TextureFormat::ASTC8x6UnormSrgb: 411 case wgpu::TextureFormat::ASTC8x8Unorm: 412 case wgpu::TextureFormat::ASTC8x8UnormSrgb: 413 case wgpu::TextureFormat::ASTC10x5Unorm: 414 case wgpu::TextureFormat::ASTC10x5UnormSrgb: 415 case wgpu::TextureFormat::ASTC10x6Unorm: 416 case wgpu::TextureFormat::ASTC10x6UnormSrgb: 417 case wgpu::TextureFormat::ASTC10x8Unorm: 418 case wgpu::TextureFormat::ASTC10x8UnormSrgb: 419 case wgpu::TextureFormat::ASTC10x10Unorm: 420 case wgpu::TextureFormat::ASTC10x10UnormSrgb: 421 case wgpu::TextureFormat::ASTC12x10Unorm: 422 case wgpu::TextureFormat::ASTC12x10UnormSrgb: 423 case wgpu::TextureFormat::ASTC12x12Unorm: 424 case wgpu::TextureFormat::ASTC12x12UnormSrgb: 425 426 // TODO(dawn:666): implement stencil8 427 case wgpu::TextureFormat::Stencil8: 428 // TODO(dawn:690): implement depth24unorm-stencil8 429 case wgpu::TextureFormat::Depth24UnormStencil8: 430 // TODO(dawn:690): implement depth32float-stencil8 431 case wgpu::TextureFormat::Depth32FloatStencil8: 432 case wgpu::TextureFormat::Undefined: 433 UNREACHABLE(); 434 } 435 } 436 ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor * descriptor)437 MaybeError ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor* descriptor) { 438 DAWN_INVALID_IF(descriptor->dimension != wgpu::TextureDimension::e2D, 439 "Texture dimension (%s) is not %s.", descriptor->dimension, 440 wgpu::TextureDimension::e2D); 441 442 DAWN_INVALID_IF(descriptor->mipLevelCount != 1, "Mip level count (%u) is not 1.", 443 descriptor->mipLevelCount); 444 445 DAWN_INVALID_IF(descriptor->size.depthOrArrayLayers != 1, 446 "Array layer count (%u) is not 1.", descriptor->size.depthOrArrayLayers); 447 448 DAWN_INVALID_IF(descriptor->sampleCount != 1, "Sample count (%u) is not 1.", 449 descriptor->sampleCount); 450 451 return {}; 452 } 453 ValidateD3D12TextureCanBeWrapped(ID3D12Resource * d3d12Resource,const TextureDescriptor * dawnDescriptor)454 MaybeError ValidateD3D12TextureCanBeWrapped(ID3D12Resource* d3d12Resource, 455 const TextureDescriptor* dawnDescriptor) { 456 const D3D12_RESOURCE_DESC d3dDescriptor = d3d12Resource->GetDesc(); 457 DAWN_INVALID_IF( 458 (dawnDescriptor->size.width != d3dDescriptor.Width) || 459 (dawnDescriptor->size.height != d3dDescriptor.Height) || 460 (dawnDescriptor->size.depthOrArrayLayers != 1), 461 "D3D12 texture size (Width: %u, Height: %u, DepthOrArraySize: 1) doesn't match Dawn " 462 "descriptor size (width: %u, height: %u, depthOrArrayLayers: %u).", 463 d3dDescriptor.Width, d3dDescriptor.Height, dawnDescriptor->size.width, 464 dawnDescriptor->size.height, dawnDescriptor->size.depthOrArrayLayers); 465 466 const DXGI_FORMAT dxgiFormatFromDescriptor = D3D12TextureFormat(dawnDescriptor->format); 467 DAWN_INVALID_IF( 468 dxgiFormatFromDescriptor != d3dDescriptor.Format, 469 "D3D12 texture format (%x) is not compatible with Dawn descriptor format (%s).", 470 d3dDescriptor.Format, dawnDescriptor->format); 471 472 DAWN_INVALID_IF(d3dDescriptor.MipLevels != 1, 473 "D3D12 texture number of miplevels (%u) is not 1.", 474 d3dDescriptor.MipLevels); 475 476 DAWN_INVALID_IF(d3dDescriptor.DepthOrArraySize != 1, 477 "D3D12 texture array size (%u) is not 1.", d3dDescriptor.DepthOrArraySize); 478 479 // Shared textures cannot be multi-sample so no need to check those. 480 ASSERT(d3dDescriptor.SampleDesc.Count == 1); 481 ASSERT(d3dDescriptor.SampleDesc.Quality == 0); 482 483 return {}; 484 } 485 486 // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_shared_resource_compatibility_tier ValidateD3D12VideoTextureCanBeShared(Device * device,DXGI_FORMAT textureFormat)487 MaybeError ValidateD3D12VideoTextureCanBeShared(Device* device, DXGI_FORMAT textureFormat) { 488 const bool supportsSharedResourceCapabilityTier1 = 489 device->GetDeviceInfo().supportsSharedResourceCapabilityTier1; 490 switch (textureFormat) { 491 // MSDN docs are not correct, NV12 requires at-least tier 1. 492 case DXGI_FORMAT_NV12: 493 if (supportsSharedResourceCapabilityTier1) { 494 return {}; 495 } 496 break; 497 default: 498 break; 499 } 500 501 return DAWN_FORMAT_VALIDATION_ERROR("DXGI format does not support cross-API sharing."); 502 } 503 504 // static Create(Device * device,const TextureDescriptor * descriptor)505 ResultOrError<Ref<Texture>> Texture::Create(Device* device, 506 const TextureDescriptor* descriptor) { 507 Ref<Texture> dawnTexture = 508 AcquireRef(new Texture(device, descriptor, TextureState::OwnedInternal)); 509 510 DAWN_INVALID_IF(dawnTexture->GetFormat().IsMultiPlanar(), 511 "Cannot create a multi-planar formatted texture directly"); 512 513 DAWN_TRY(dawnTexture->InitializeAsInternalTexture()); 514 return std::move(dawnTexture); 515 } 516 517 // static CreateExternalImage(Device * device,const TextureDescriptor * descriptor,ComPtr<ID3D12Resource> d3d12Texture,Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,ExternalMutexSerial acquireMutexKey,ExternalMutexSerial releaseMutexKey,bool isSwapChainTexture,bool isInitialized)518 ResultOrError<Ref<Texture>> Texture::CreateExternalImage( 519 Device* device, 520 const TextureDescriptor* descriptor, 521 ComPtr<ID3D12Resource> d3d12Texture, 522 Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource, 523 ExternalMutexSerial acquireMutexKey, 524 ExternalMutexSerial releaseMutexKey, 525 bool isSwapChainTexture, 526 bool isInitialized) { 527 Ref<Texture> dawnTexture = 528 AcquireRef(new Texture(device, descriptor, TextureState::OwnedExternal)); 529 DAWN_TRY(dawnTexture->InitializeAsExternalTexture( 530 descriptor, std::move(d3d12Texture), std::move(d3d11on12Resource), acquireMutexKey, 531 releaseMutexKey, isSwapChainTexture)); 532 533 // Importing a multi-planar format must be initialized. This is required because 534 // a shared multi-planar format cannot be initialized by Dawn. 535 DAWN_INVALID_IF( 536 !isInitialized && dawnTexture->GetFormat().IsMultiPlanar(), 537 "Cannot create a texture with a multi-planar format (%s) with uninitialized data.", 538 dawnTexture->GetFormat().format); 539 540 dawnTexture->SetIsSubresourceContentInitialized(isInitialized, 541 dawnTexture->GetAllSubresources()); 542 return std::move(dawnTexture); 543 } 544 545 // static Create(Device * device,const TextureDescriptor * descriptor,ComPtr<ID3D12Resource> d3d12Texture)546 ResultOrError<Ref<Texture>> Texture::Create(Device* device, 547 const TextureDescriptor* descriptor, 548 ComPtr<ID3D12Resource> d3d12Texture) { 549 Ref<Texture> dawnTexture = 550 AcquireRef(new Texture(device, descriptor, TextureState::OwnedExternal)); 551 DAWN_TRY(dawnTexture->InitializeAsSwapChainTexture(std::move(d3d12Texture))); 552 return std::move(dawnTexture); 553 } 554 InitializeAsExternalTexture(const TextureDescriptor * descriptor,ComPtr<ID3D12Resource> d3d12Texture,Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,ExternalMutexSerial acquireMutexKey,ExternalMutexSerial releaseMutexKey,bool isSwapChainTexture)555 MaybeError Texture::InitializeAsExternalTexture( 556 const TextureDescriptor* descriptor, 557 ComPtr<ID3D12Resource> d3d12Texture, 558 Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource, 559 ExternalMutexSerial acquireMutexKey, 560 ExternalMutexSerial releaseMutexKey, 561 bool isSwapChainTexture) { 562 DAWN_TRY(CheckHRESULT(d3d11on12Resource->GetDXGIKeyedMutex()->AcquireSync( 563 uint64_t(acquireMutexKey), INFINITE), 564 "D3D12 acquiring shared mutex")); 565 566 mAcquireMutexKey = acquireMutexKey; 567 mReleaseMutexKey = releaseMutexKey; 568 mD3D11on12Resource = std::move(d3d11on12Resource); 569 mSwapChainTexture = isSwapChainTexture; 570 571 D3D12_RESOURCE_DESC desc = d3d12Texture->GetDesc(); 572 mD3D12ResourceFlags = desc.Flags; 573 574 AllocationInfo info; 575 info.mMethod = AllocationMethod::kExternal; 576 // When creating the ResourceHeapAllocation, the resource heap is set to nullptr because the 577 // texture is owned externally. The texture's owning entity must remain responsible for 578 // memory management. 579 mResourceAllocation = {info, 0, std::move(d3d12Texture), nullptr}; 580 581 SetLabelHelper("Dawn_ExternalTexture"); 582 583 return {}; 584 } 585 InitializeAsInternalTexture()586 MaybeError Texture::InitializeAsInternalTexture() { 587 D3D12_RESOURCE_DESC resourceDescriptor; 588 resourceDescriptor.Dimension = D3D12TextureDimension(GetDimension()); 589 resourceDescriptor.Alignment = 0; 590 591 const Extent3D& size = GetSize(); 592 resourceDescriptor.Width = size.width; 593 resourceDescriptor.Height = size.height; 594 resourceDescriptor.DepthOrArraySize = size.depthOrArrayLayers; 595 596 // This will need to be much more nuanced when WebGPU has 597 // texture view compatibility rules. 598 const bool needsTypelessFormat = 599 GetFormat().HasDepthOrStencil() && 600 (GetInternalUsage() & wgpu::TextureUsage::TextureBinding) != 0; 601 602 DXGI_FORMAT dxgiFormat = needsTypelessFormat 603 ? D3D12TypelessTextureFormat(GetFormat().format) 604 : D3D12TextureFormat(GetFormat().format); 605 606 resourceDescriptor.MipLevels = static_cast<UINT16>(GetNumMipLevels()); 607 resourceDescriptor.Format = dxgiFormat; 608 resourceDescriptor.SampleDesc.Count = GetSampleCount(); 609 resourceDescriptor.SampleDesc.Quality = 0; 610 resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; 611 resourceDescriptor.Flags = 612 D3D12ResourceFlags(GetInternalUsage(), GetFormat(), IsMultisampledTexture()); 613 mD3D12ResourceFlags = resourceDescriptor.Flags; 614 615 DAWN_TRY_ASSIGN(mResourceAllocation, 616 ToBackend(GetDevice()) 617 ->AllocateMemory(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor, 618 D3D12_RESOURCE_STATE_COMMON)); 619 620 SetLabelImpl(); 621 622 Device* device = ToBackend(GetDevice()); 623 624 if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) { 625 CommandRecordingContext* commandContext; 626 DAWN_TRY_ASSIGN(commandContext, device->GetPendingCommandContext()); 627 628 DAWN_TRY(ClearTexture(commandContext, GetAllSubresources(), 629 TextureBase::ClearValue::NonZero)); 630 } 631 632 return {}; 633 } 634 InitializeAsSwapChainTexture(ComPtr<ID3D12Resource> d3d12Texture)635 MaybeError Texture::InitializeAsSwapChainTexture(ComPtr<ID3D12Resource> d3d12Texture) { 636 AllocationInfo info; 637 info.mMethod = AllocationMethod::kExternal; 638 // When creating the ResourceHeapAllocation, the resource heap is set to nullptr because the 639 // texture is owned externally. The texture's owning entity must remain responsible for 640 // memory management. 641 mResourceAllocation = {info, 0, std::move(d3d12Texture), nullptr}; 642 643 SetLabelHelper("Dawn_SwapChainTexture"); 644 645 return {}; 646 } 647 Texture(Device * device,const TextureDescriptor * descriptor,TextureState state)648 Texture::Texture(Device* device, const TextureDescriptor* descriptor, TextureState state) 649 : TextureBase(device, descriptor, state), 650 mSubresourceStateAndDecay( 651 GetFormat().aspects, 652 GetArrayLayers(), 653 GetNumMipLevels(), 654 {D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_COMMON, kMaxExecutionSerial, false}) { 655 } 656 ~Texture()657 Texture::~Texture() { 658 } 659 DestroyImpl()660 void Texture::DestroyImpl() { 661 TextureBase::DestroyImpl(); 662 663 Device* device = ToBackend(GetDevice()); 664 665 // In PIX's D3D12-only mode, there is no way to determine frame boundaries 666 // for WebGPU since Dawn does not manage DXGI swap chains. Without assistance, 667 // PIX will wait forever for a present that never happens. 668 // If we know we're dealing with a swapbuffer texture, inform PIX we've 669 // "presented" the texture so it can determine frame boundaries and use its 670 // contents for the UI. 671 if (mSwapChainTexture) { 672 ID3D12SharingContract* d3dSharingContract = device->GetSharingContract(); 673 if (d3dSharingContract != nullptr) { 674 d3dSharingContract->Present(mResourceAllocation.GetD3D12Resource(), 0, 0); 675 } 676 } 677 678 device->DeallocateMemory(mResourceAllocation); 679 680 // Now that we've deallocated the memory, the texture is no longer a swap chain texture. 681 // We can set mSwapChainTexture to false to avoid passing a nullptr to 682 // ID3D12SharingContract::Present. 683 mSwapChainTexture = false; 684 685 if (mD3D11on12Resource != nullptr) { 686 mD3D11on12Resource->GetDXGIKeyedMutex()->ReleaseSync(uint64_t(mReleaseMutexKey)); 687 } 688 } 689 GetD3D12Format() const690 DXGI_FORMAT Texture::GetD3D12Format() const { 691 return D3D12TextureFormat(GetFormat().format); 692 } 693 GetD3D12Resource() const694 ID3D12Resource* Texture::GetD3D12Resource() const { 695 return mResourceAllocation.GetD3D12Resource(); 696 } 697 GetD3D12CopyableSubresourceFormat(Aspect aspect) const698 DXGI_FORMAT Texture::GetD3D12CopyableSubresourceFormat(Aspect aspect) const { 699 ASSERT(GetFormat().aspects & aspect); 700 701 switch (GetFormat().format) { 702 case wgpu::TextureFormat::Depth24PlusStencil8: 703 switch (aspect) { 704 case Aspect::Depth: 705 return DXGI_FORMAT_R32_FLOAT; 706 case Aspect::Stencil: 707 return DXGI_FORMAT_R8_UINT; 708 default: 709 UNREACHABLE(); 710 } 711 default: 712 ASSERT(HasOneBit(GetFormat().aspects)); 713 return GetD3D12Format(); 714 } 715 } 716 TrackUsageAndTransitionNow(CommandRecordingContext * commandContext,wgpu::TextureUsage usage,const SubresourceRange & range)717 void Texture::TrackUsageAndTransitionNow(CommandRecordingContext* commandContext, 718 wgpu::TextureUsage usage, 719 const SubresourceRange& range) { 720 TrackUsageAndTransitionNow(commandContext, D3D12TextureUsage(usage, GetFormat()), range); 721 } 722 TrackAllUsageAndTransitionNow(CommandRecordingContext * commandContext,wgpu::TextureUsage usage)723 void Texture::TrackAllUsageAndTransitionNow(CommandRecordingContext* commandContext, 724 wgpu::TextureUsage usage) { 725 TrackUsageAndTransitionNow(commandContext, D3D12TextureUsage(usage, GetFormat()), 726 GetAllSubresources()); 727 } 728 TrackAllUsageAndTransitionNow(CommandRecordingContext * commandContext,D3D12_RESOURCE_STATES newState)729 void Texture::TrackAllUsageAndTransitionNow(CommandRecordingContext* commandContext, 730 D3D12_RESOURCE_STATES newState) { 731 TrackUsageAndTransitionNow(commandContext, newState, GetAllSubresources()); 732 } 733 TrackUsageAndTransitionNow(CommandRecordingContext * commandContext,D3D12_RESOURCE_STATES newState,const SubresourceRange & range)734 void Texture::TrackUsageAndTransitionNow(CommandRecordingContext* commandContext, 735 D3D12_RESOURCE_STATES newState, 736 const SubresourceRange& range) { 737 if (mResourceAllocation.GetInfo().mMethod != AllocationMethod::kExternal) { 738 // Track the underlying heap to ensure residency. 739 Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap()); 740 commandContext->TrackHeapUsage(heap, GetDevice()->GetPendingCommandSerial()); 741 } 742 743 std::vector<D3D12_RESOURCE_BARRIER> barriers; 744 745 // TODO(enga): Consider adding a Count helper. 746 uint32_t aspectCount = 0; 747 for (Aspect aspect : IterateEnumMask(range.aspects)) { 748 aspectCount++; 749 DAWN_UNUSED(aspect); 750 } 751 752 barriers.reserve(range.levelCount * range.layerCount * aspectCount); 753 754 TransitionUsageAndGetResourceBarrier(commandContext, &barriers, newState, range); 755 if (barriers.size()) { 756 commandContext->GetCommandList()->ResourceBarrier(barriers.size(), barriers.data()); 757 } 758 } 759 TransitionSubresourceRange(std::vector<D3D12_RESOURCE_BARRIER> * barriers,const SubresourceRange & range,StateAndDecay * state,D3D12_RESOURCE_STATES newState,ExecutionSerial pendingCommandSerial) const760 void Texture::TransitionSubresourceRange(std::vector<D3D12_RESOURCE_BARRIER>* barriers, 761 const SubresourceRange& range, 762 StateAndDecay* state, 763 D3D12_RESOURCE_STATES newState, 764 ExecutionSerial pendingCommandSerial) const { 765 // Reuse the subresource(s) directly and avoid transition when it isn't needed, and 766 // return false. 767 if (state->lastState == newState) { 768 return; 769 } 770 771 D3D12_RESOURCE_STATES lastState = state->lastState; 772 773 // The COMMON state represents a state where no write operations can be pending, and 774 // where all pixels are uncompressed. This makes it possible to transition to and 775 // from some states without synchronization (i.e. without an explicit 776 // ResourceBarrier call). Textures can be implicitly promoted to 1) a single write 777 // state, or 2) multiple read states. Textures will implicitly decay to the COMMON 778 // state when all of the following are true: 1) the texture is accessed on a command 779 // list, 2) the ExecuteCommandLists call that uses that command list has ended, and 780 // 3) the texture was promoted implicitly to a read-only state and is still in that 781 // state. 782 // https://docs.microsoft.com/en-us/windows/desktop/direct3d12/using-resource-barriers-to-synchronize-resource-states-in-direct3d-12#implicit-state-transitions 783 784 // To track implicit decays, we must record the pending serial on which that 785 // transition will occur. When that texture is used again, the previously recorded 786 // serial must be compared to the last completed serial to determine if the texture 787 // has implicity decayed to the common state. 788 if (state->isValidToDecay && pendingCommandSerial > state->lastDecaySerial) { 789 lastState = D3D12_RESOURCE_STATE_COMMON; 790 } 791 792 // Update the tracked state. 793 state->lastState = newState; 794 795 // Destination states that qualify for an implicit promotion for a 796 // non-simultaneous-access texture: NON_PIXEL_SHADER_RESOURCE, 797 // PIXEL_SHADER_RESOURCE, COPY_SRC, COPY_DEST. 798 { 799 static constexpr D3D12_RESOURCE_STATES kD3D12PromotableReadOnlyStates = 800 D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | 801 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; 802 803 if (lastState == D3D12_RESOURCE_STATE_COMMON) { 804 if (IsSubset(newState, kD3D12PromotableReadOnlyStates)) { 805 // Implicit texture state decays can only occur when the texture was implicitly 806 // transitioned to a read-only state. isValidToDecay is needed to differentiate 807 // between resources that were implictly or explicitly transitioned to a 808 // read-only state. 809 state->isValidToDecay = true; 810 state->lastDecaySerial = pendingCommandSerial; 811 return; 812 } else if (newState == D3D12_RESOURCE_STATE_COPY_DEST) { 813 state->isValidToDecay = false; 814 return; 815 } 816 } 817 } 818 819 D3D12_RESOURCE_BARRIER barrier; 820 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; 821 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; 822 barrier.Transition.pResource = GetD3D12Resource(); 823 barrier.Transition.StateBefore = lastState; 824 barrier.Transition.StateAfter = newState; 825 826 bool isFullRange = range.baseArrayLayer == 0 && range.baseMipLevel == 0 && 827 range.layerCount == GetArrayLayers() && 828 range.levelCount == GetNumMipLevels() && 829 range.aspects == GetFormat().aspects; 830 831 // Use a single transition for all subresources if possible. 832 if (isFullRange) { 833 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; 834 barriers->push_back(barrier); 835 } else { 836 for (Aspect aspect : IterateEnumMask(range.aspects)) { 837 for (uint32_t arrayLayer = 0; arrayLayer < range.layerCount; ++arrayLayer) { 838 for (uint32_t mipLevel = 0; mipLevel < range.levelCount; ++mipLevel) { 839 barrier.Transition.Subresource = 840 GetSubresourceIndex(range.baseMipLevel + mipLevel, 841 range.baseArrayLayer + arrayLayer, aspect); 842 barriers->push_back(barrier); 843 } 844 } 845 } 846 } 847 848 state->isValidToDecay = false; 849 } 850 HandleTransitionSpecialCases(CommandRecordingContext * commandContext)851 void Texture::HandleTransitionSpecialCases(CommandRecordingContext* commandContext) { 852 // Textures with keyed mutexes can be written from other graphics queues. Hence, they 853 // must be acquired before command list submission to ensure work from the other queues 854 // has finished. See Device::ExecuteCommandContext. 855 if (mD3D11on12Resource != nullptr) { 856 commandContext->AddToSharedTextureList(this); 857 } 858 } 859 TransitionUsageAndGetResourceBarrier(CommandRecordingContext * commandContext,std::vector<D3D12_RESOURCE_BARRIER> * barrier,wgpu::TextureUsage usage,const SubresourceRange & range)860 void Texture::TransitionUsageAndGetResourceBarrier(CommandRecordingContext* commandContext, 861 std::vector<D3D12_RESOURCE_BARRIER>* barrier, 862 wgpu::TextureUsage usage, 863 const SubresourceRange& range) { 864 TransitionUsageAndGetResourceBarrier(commandContext, barrier, 865 D3D12TextureUsage(usage, GetFormat()), range); 866 } 867 TransitionUsageAndGetResourceBarrier(CommandRecordingContext * commandContext,std::vector<D3D12_RESOURCE_BARRIER> * barriers,D3D12_RESOURCE_STATES newState,const SubresourceRange & range)868 void Texture::TransitionUsageAndGetResourceBarrier( 869 CommandRecordingContext* commandContext, 870 std::vector<D3D12_RESOURCE_BARRIER>* barriers, 871 D3D12_RESOURCE_STATES newState, 872 const SubresourceRange& range) { 873 HandleTransitionSpecialCases(commandContext); 874 875 const ExecutionSerial pendingCommandSerial = 876 ToBackend(GetDevice())->GetPendingCommandSerial(); 877 878 ASSERT(GetDimension() != wgpu::TextureDimension::e1D); 879 880 mSubresourceStateAndDecay.Update( 881 range, [&](const SubresourceRange& updateRange, StateAndDecay* state) { 882 TransitionSubresourceRange(barriers, updateRange, state, newState, 883 pendingCommandSerial); 884 }); 885 } 886 TrackUsageAndGetResourceBarrierForPass(CommandRecordingContext * commandContext,std::vector<D3D12_RESOURCE_BARRIER> * barriers,const TextureSubresourceUsage & textureUsages)887 void Texture::TrackUsageAndGetResourceBarrierForPass( 888 CommandRecordingContext* commandContext, 889 std::vector<D3D12_RESOURCE_BARRIER>* barriers, 890 const TextureSubresourceUsage& textureUsages) { 891 if (mResourceAllocation.GetInfo().mMethod != AllocationMethod::kExternal) { 892 // Track the underlying heap to ensure residency. 893 Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap()); 894 commandContext->TrackHeapUsage(heap, GetDevice()->GetPendingCommandSerial()); 895 } 896 897 HandleTransitionSpecialCases(commandContext); 898 899 const ExecutionSerial pendingCommandSerial = 900 ToBackend(GetDevice())->GetPendingCommandSerial(); 901 // TODO(crbug.com/dawn/814): support 1D textures. 902 ASSERT(GetDimension() != wgpu::TextureDimension::e1D); 903 904 mSubresourceStateAndDecay.Merge(textureUsages, [&](const SubresourceRange& mergeRange, 905 StateAndDecay* state, 906 wgpu::TextureUsage usage) { 907 // Skip if this subresource is not used during the current pass 908 if (usage == wgpu::TextureUsage::None) { 909 return; 910 } 911 912 D3D12_RESOURCE_STATES newState = D3D12TextureUsage(usage, GetFormat()); 913 TransitionSubresourceRange(barriers, mergeRange, state, newState, pendingCommandSerial); 914 }); 915 } 916 GetRTVDescriptor(uint32_t mipLevel,uint32_t baseSlice,uint32_t sliceCount) const917 D3D12_RENDER_TARGET_VIEW_DESC Texture::GetRTVDescriptor(uint32_t mipLevel, 918 uint32_t baseSlice, 919 uint32_t sliceCount) const { 920 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; 921 rtvDesc.Format = GetD3D12Format(); 922 if (IsMultisampledTexture()) { 923 ASSERT(GetDimension() == wgpu::TextureDimension::e2D); 924 ASSERT(GetNumMipLevels() == 1); 925 ASSERT(sliceCount == 1); 926 ASSERT(baseSlice == 0); 927 ASSERT(mipLevel == 0); 928 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS; 929 return rtvDesc; 930 } 931 switch (GetDimension()) { 932 case wgpu::TextureDimension::e2D: 933 // Currently we always use D3D12_TEX2D_ARRAY_RTV because we cannot specify base 934 // array layer and layer count in D3D12_TEX2D_RTV. For 2D texture views, we treat 935 // them as 1-layer 2D array textures. (Just like how we treat SRVs) 936 // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_rtv 937 // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_array 938 // _rtv 939 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; 940 rtvDesc.Texture2DArray.FirstArraySlice = baseSlice; 941 rtvDesc.Texture2DArray.ArraySize = sliceCount; 942 rtvDesc.Texture2DArray.MipSlice = mipLevel; 943 rtvDesc.Texture2DArray.PlaneSlice = 0; 944 break; 945 case wgpu::TextureDimension::e3D: 946 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; 947 rtvDesc.Texture3D.MipSlice = mipLevel; 948 rtvDesc.Texture3D.FirstWSlice = baseSlice; 949 rtvDesc.Texture3D.WSize = sliceCount; 950 break; 951 case wgpu::TextureDimension::e1D: 952 UNREACHABLE(); 953 break; 954 } 955 return rtvDesc; 956 } 957 GetDSVDescriptor(uint32_t mipLevel,uint32_t baseArrayLayer,uint32_t layerCount,Aspect aspects,bool depthReadOnly,bool stencilReadOnly) const958 D3D12_DEPTH_STENCIL_VIEW_DESC Texture::GetDSVDescriptor(uint32_t mipLevel, 959 uint32_t baseArrayLayer, 960 uint32_t layerCount, 961 Aspect aspects, 962 bool depthReadOnly, 963 bool stencilReadOnly) const { 964 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc; 965 dsvDesc.Format = GetD3D12Format(); 966 dsvDesc.Flags = D3D12_DSV_FLAG_NONE; 967 if (depthReadOnly && aspects & Aspect::Depth) { 968 dsvDesc.Flags |= D3D12_DSV_FLAG_READ_ONLY_DEPTH; 969 } 970 if (stencilReadOnly && aspects & Aspect::Stencil) { 971 dsvDesc.Flags |= D3D12_DSV_FLAG_READ_ONLY_STENCIL; 972 } 973 974 if (IsMultisampledTexture()) { 975 ASSERT(GetNumMipLevels() == 1); 976 ASSERT(layerCount == 1); 977 ASSERT(baseArrayLayer == 0); 978 ASSERT(mipLevel == 0); 979 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS; 980 } else { 981 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY; 982 dsvDesc.Texture2DArray.FirstArraySlice = baseArrayLayer; 983 dsvDesc.Texture2DArray.ArraySize = layerCount; 984 dsvDesc.Texture2DArray.MipSlice = mipLevel; 985 } 986 987 return dsvDesc; 988 } 989 ClearTexture(CommandRecordingContext * commandContext,const SubresourceRange & range,TextureBase::ClearValue clearValue)990 MaybeError Texture::ClearTexture(CommandRecordingContext* commandContext, 991 const SubresourceRange& range, 992 TextureBase::ClearValue clearValue) { 993 ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList(); 994 995 Device* device = ToBackend(GetDevice()); 996 997 uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1; 998 float fClearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0.f : 1.f; 999 1000 if ((mD3D12ResourceFlags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) != 0) { 1001 TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE, range); 1002 1003 for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount; 1004 ++level) { 1005 for (uint32_t layer = range.baseArrayLayer; 1006 layer < range.baseArrayLayer + range.layerCount; ++layer) { 1007 // Iterate the aspects individually to determine which clear flags to use. 1008 D3D12_CLEAR_FLAGS clearFlags = {}; 1009 for (Aspect aspect : IterateEnumMask(range.aspects)) { 1010 if (clearValue == TextureBase::ClearValue::Zero && 1011 IsSubresourceContentInitialized( 1012 SubresourceRange::SingleMipAndLayer(level, layer, aspect))) { 1013 // Skip lazy clears if already initialized. 1014 continue; 1015 } 1016 1017 switch (aspect) { 1018 case Aspect::Depth: 1019 clearFlags |= D3D12_CLEAR_FLAG_DEPTH; 1020 break; 1021 case Aspect::Stencil: 1022 clearFlags |= D3D12_CLEAR_FLAG_STENCIL; 1023 break; 1024 default: 1025 UNREACHABLE(); 1026 } 1027 } 1028 1029 if (clearFlags == 0) { 1030 continue; 1031 } 1032 1033 CPUDescriptorHeapAllocation dsvHandle; 1034 DAWN_TRY_ASSIGN( 1035 dsvHandle, 1036 device->GetDepthStencilViewAllocator()->AllocateTransientCPUDescriptors()); 1037 const D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor = 1038 dsvHandle.GetBaseDescriptor(); 1039 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = 1040 GetDSVDescriptor(level, layer, 1, range.aspects, false, false); 1041 device->GetD3D12Device()->CreateDepthStencilView(GetD3D12Resource(), &dsvDesc, 1042 baseDescriptor); 1043 1044 commandList->ClearDepthStencilView(baseDescriptor, clearFlags, fClearColor, 1045 clearColor, 0, nullptr); 1046 } 1047 } 1048 } else if ((mD3D12ResourceFlags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) != 0) { 1049 TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_RENDER_TARGET, range); 1050 1051 const float clearColorRGBA[4] = {fClearColor, fClearColor, fClearColor, fClearColor}; 1052 1053 ASSERT(range.aspects == Aspect::Color); 1054 for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount; 1055 ++level) { 1056 for (uint32_t layer = range.baseArrayLayer; 1057 layer < range.baseArrayLayer + range.layerCount; ++layer) { 1058 if (clearValue == TextureBase::ClearValue::Zero && 1059 IsSubresourceContentInitialized( 1060 SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) { 1061 // Skip lazy clears if already initialized. 1062 continue; 1063 } 1064 1065 CPUDescriptorHeapAllocation rtvHeap; 1066 DAWN_TRY_ASSIGN( 1067 rtvHeap, 1068 device->GetRenderTargetViewAllocator()->AllocateTransientCPUDescriptors()); 1069 const D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetBaseDescriptor(); 1070 1071 uint32_t baseSlice = layer; 1072 uint32_t sliceCount = 1; 1073 if (GetDimension() == wgpu::TextureDimension::e3D) { 1074 baseSlice = 0; 1075 sliceCount = std::max(GetDepth() >> level, 1u); 1076 } 1077 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = 1078 GetRTVDescriptor(level, baseSlice, sliceCount); 1079 device->GetD3D12Device()->CreateRenderTargetView(GetD3D12Resource(), &rtvDesc, 1080 rtvHandle); 1081 commandList->ClearRenderTargetView(rtvHandle, clearColorRGBA, 0, nullptr); 1082 } 1083 } 1084 } else { 1085 // create temp buffer with clear color to copy to the texture image 1086 TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_COPY_DEST, range); 1087 1088 for (Aspect aspect : IterateEnumMask(range.aspects)) { 1089 const TexelBlockInfo& blockInfo = GetFormat().GetAspectInfo(aspect).block; 1090 1091 Extent3D largestMipSize = GetMipLevelPhysicalSize(range.baseMipLevel); 1092 1093 uint32_t bytesPerRow = 1094 Align((largestMipSize.width / blockInfo.width) * blockInfo.byteSize, 1095 kTextureBytesPerRowAlignment); 1096 uint64_t bufferSize = bytesPerRow * (largestMipSize.height / blockInfo.height) * 1097 largestMipSize.depthOrArrayLayers; 1098 DynamicUploader* uploader = device->GetDynamicUploader(); 1099 UploadHandle uploadHandle; 1100 DAWN_TRY_ASSIGN(uploadHandle, 1101 uploader->Allocate(bufferSize, device->GetPendingCommandSerial(), 1102 blockInfo.byteSize)); 1103 memset(uploadHandle.mappedBuffer, clearColor, bufferSize); 1104 1105 for (uint32_t level = range.baseMipLevel; 1106 level < range.baseMipLevel + range.levelCount; ++level) { 1107 // compute d3d12 texture copy locations for texture and buffer 1108 Extent3D copySize = GetMipLevelPhysicalSize(level); 1109 1110 TextureCopySubresource copySplit = Compute2DTextureCopySubresource( 1111 {0, 0, 0}, copySize, blockInfo, uploadHandle.startOffset, bytesPerRow); 1112 1113 for (uint32_t layer = range.baseArrayLayer; 1114 layer < range.baseArrayLayer + range.layerCount; ++layer) { 1115 if (clearValue == TextureBase::ClearValue::Zero && 1116 IsSubresourceContentInitialized( 1117 SubresourceRange::SingleMipAndLayer(level, layer, aspect))) { 1118 // Skip lazy clears if already initialized. 1119 continue; 1120 } 1121 1122 RecordCopyBufferToTextureFromTextureCopySplit( 1123 commandList, copySplit, 1124 ToBackend(uploadHandle.stagingBuffer)->GetResource(), 0, bytesPerRow, 1125 this, level, layer, aspect); 1126 } 1127 } 1128 } 1129 } 1130 if (clearValue == TextureBase::ClearValue::Zero) { 1131 SetIsSubresourceContentInitialized(true, range); 1132 GetDevice()->IncrementLazyClearCountForTesting(); 1133 } 1134 return {}; 1135 } 1136 SetLabelHelper(const char * prefix)1137 void Texture::SetLabelHelper(const char* prefix) { 1138 SetDebugName(ToBackend(GetDevice()), mResourceAllocation.GetD3D12Resource(), prefix, 1139 GetLabel()); 1140 } 1141 SetLabelImpl()1142 void Texture::SetLabelImpl() { 1143 SetLabelHelper("Dawn_InternalTexture"); 1144 } 1145 EnsureSubresourceContentInitialized(CommandRecordingContext * commandContext,const SubresourceRange & range)1146 void Texture::EnsureSubresourceContentInitialized(CommandRecordingContext* commandContext, 1147 const SubresourceRange& range) { 1148 if (!ToBackend(GetDevice())->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse)) { 1149 return; 1150 } 1151 if (!IsSubresourceContentInitialized(range)) { 1152 // If subresource has not been initialized, clear it to black as it could contain 1153 // dirty bits from recycled memory 1154 GetDevice()->ConsumedError( 1155 ClearTexture(commandContext, range, TextureBase::ClearValue::Zero)); 1156 } 1157 } 1158 operator ==(const Texture::StateAndDecay & other) const1159 bool Texture::StateAndDecay::operator==(const Texture::StateAndDecay& other) const { 1160 return lastState == other.lastState && lastDecaySerial == other.lastDecaySerial && 1161 isValidToDecay == other.isValidToDecay; 1162 } 1163 1164 // static Create(TextureBase * texture,const TextureViewDescriptor * descriptor)1165 Ref<TextureView> TextureView::Create(TextureBase* texture, 1166 const TextureViewDescriptor* descriptor) { 1167 return AcquireRef(new TextureView(texture, descriptor)); 1168 } 1169 TextureView(TextureBase * texture,const TextureViewDescriptor * descriptor)1170 TextureView::TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor) 1171 : TextureViewBase(texture, descriptor) { 1172 mSrvDesc.Format = D3D12TextureFormat(descriptor->format); 1173 mSrvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; 1174 1175 // TODO(enga): This will need to be much more nuanced when WebGPU has 1176 // texture view compatibility rules. 1177 UINT planeSlice = 0; 1178 if (GetFormat().HasDepthOrStencil()) { 1179 // Configure the SRV descriptor to reinterpret the texture allocated as 1180 // TYPELESS as a single-plane shader-accessible view. 1181 switch (descriptor->format) { 1182 case wgpu::TextureFormat::Depth32Float: 1183 case wgpu::TextureFormat::Depth24Plus: 1184 mSrvDesc.Format = DXGI_FORMAT_R32_FLOAT; 1185 break; 1186 case wgpu::TextureFormat::Depth16Unorm: 1187 mSrvDesc.Format = DXGI_FORMAT_R16_UNORM; 1188 break; 1189 case wgpu::TextureFormat::Depth24PlusStencil8: 1190 switch (descriptor->aspect) { 1191 case wgpu::TextureAspect::DepthOnly: 1192 planeSlice = 0; 1193 mSrvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; 1194 break; 1195 case wgpu::TextureAspect::StencilOnly: 1196 planeSlice = 1; 1197 mSrvDesc.Format = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; 1198 // Stencil is accessed using the .g component in the shader. 1199 // Map it to the zeroth component to match other APIs. 1200 mSrvDesc.Shader4ComponentMapping = 1201 D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( 1202 D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, 1203 D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, 1204 D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, 1205 D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1); 1206 break; 1207 case wgpu::TextureAspect::All: 1208 // A single aspect is not selected. The texture view must not be 1209 // sampled. 1210 mSrvDesc.Format = DXGI_FORMAT_UNKNOWN; 1211 break; 1212 1213 // Depth formats cannot use plane aspects. 1214 case wgpu::TextureAspect::Plane0Only: 1215 case wgpu::TextureAspect::Plane1Only: 1216 UNREACHABLE(); 1217 break; 1218 } 1219 break; 1220 default: 1221 UNREACHABLE(); 1222 break; 1223 } 1224 } 1225 1226 // Per plane view formats must have the plane slice number be the index of the plane in the 1227 // array of textures. 1228 if (texture->GetFormat().IsMultiPlanar()) { 1229 const Aspect planeAspect = ConvertViewAspect(GetFormat(), descriptor->aspect); 1230 planeSlice = GetAspectIndex(planeAspect); 1231 mSrvDesc.Format = D3D12TextureFormat(GetFormat().GetAspectInfo(planeAspect).format); 1232 } 1233 1234 // Currently we always use D3D12_TEX2D_ARRAY_SRV because we cannot specify base array layer 1235 // and layer count in D3D12_TEX2D_SRV. For 2D texture views, we treat them as 1-layer 2D 1236 // array textures. 1237 // Multisampled textures may only be one array layer, so we use 1238 // D3D12_SRV_DIMENSION_TEXTURE2DMS. 1239 // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_srv 1240 // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_array_srv 1241 // TODO(crbug.com/dawn/814): support 1D textures. 1242 if (GetTexture()->IsMultisampledTexture()) { 1243 switch (descriptor->dimension) { 1244 case wgpu::TextureViewDimension::e2DArray: 1245 ASSERT(texture->GetArrayLayers() == 1); 1246 DAWN_FALLTHROUGH; 1247 case wgpu::TextureViewDimension::e2D: 1248 ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); 1249 mSrvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS; 1250 break; 1251 1252 default: 1253 UNREACHABLE(); 1254 } 1255 } else { 1256 switch (descriptor->dimension) { 1257 case wgpu::TextureViewDimension::e2D: 1258 case wgpu::TextureViewDimension::e2DArray: 1259 ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); 1260 mSrvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; 1261 mSrvDesc.Texture2DArray.ArraySize = descriptor->arrayLayerCount; 1262 mSrvDesc.Texture2DArray.FirstArraySlice = descriptor->baseArrayLayer; 1263 mSrvDesc.Texture2DArray.MipLevels = descriptor->mipLevelCount; 1264 mSrvDesc.Texture2DArray.MostDetailedMip = descriptor->baseMipLevel; 1265 mSrvDesc.Texture2DArray.PlaneSlice = planeSlice; 1266 mSrvDesc.Texture2DArray.ResourceMinLODClamp = 0; 1267 break; 1268 case wgpu::TextureViewDimension::Cube: 1269 case wgpu::TextureViewDimension::CubeArray: 1270 ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); 1271 ASSERT(descriptor->arrayLayerCount % 6 == 0); 1272 mSrvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; 1273 mSrvDesc.TextureCubeArray.First2DArrayFace = descriptor->baseArrayLayer; 1274 mSrvDesc.TextureCubeArray.NumCubes = descriptor->arrayLayerCount / 6; 1275 mSrvDesc.TextureCubeArray.MostDetailedMip = descriptor->baseMipLevel; 1276 mSrvDesc.TextureCubeArray.MipLevels = descriptor->mipLevelCount; 1277 mSrvDesc.TextureCubeArray.ResourceMinLODClamp = 0; 1278 break; 1279 case wgpu::TextureViewDimension::e3D: 1280 ASSERT(texture->GetDimension() == wgpu::TextureDimension::e3D); 1281 mSrvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; 1282 mSrvDesc.Texture3D.MostDetailedMip = descriptor->baseMipLevel; 1283 mSrvDesc.Texture3D.MipLevels = descriptor->mipLevelCount; 1284 mSrvDesc.Texture3D.ResourceMinLODClamp = 0; 1285 break; 1286 1287 case wgpu::TextureViewDimension::e1D: 1288 case wgpu::TextureViewDimension::Undefined: 1289 UNREACHABLE(); 1290 } 1291 } 1292 } 1293 GetD3D12Format() const1294 DXGI_FORMAT TextureView::GetD3D12Format() const { 1295 return D3D12TextureFormat(GetFormat().format); 1296 } 1297 GetSRVDescriptor() const1298 const D3D12_SHADER_RESOURCE_VIEW_DESC& TextureView::GetSRVDescriptor() const { 1299 ASSERT(mSrvDesc.Format != DXGI_FORMAT_UNKNOWN); 1300 return mSrvDesc; 1301 } 1302 GetRTVDescriptor() const1303 D3D12_RENDER_TARGET_VIEW_DESC TextureView::GetRTVDescriptor() const { 1304 return ToBackend(GetTexture()) 1305 ->GetRTVDescriptor(GetBaseMipLevel(), GetBaseArrayLayer(), GetLayerCount()); 1306 } 1307 GetDSVDescriptor(bool depthReadOnly,bool stencilReadOnly) const1308 D3D12_DEPTH_STENCIL_VIEW_DESC TextureView::GetDSVDescriptor(bool depthReadOnly, 1309 bool stencilReadOnly) const { 1310 ASSERT(GetLevelCount() == 1); 1311 return ToBackend(GetTexture()) 1312 ->GetDSVDescriptor(GetBaseMipLevel(), GetBaseArrayLayer(), GetLayerCount(), 1313 GetAspects(), depthReadOnly, stencilReadOnly); 1314 } 1315 GetUAVDescriptor() const1316 D3D12_UNORDERED_ACCESS_VIEW_DESC TextureView::GetUAVDescriptor() const { 1317 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc; 1318 uavDesc.Format = GetD3D12Format(); 1319 1320 ASSERT(!GetTexture()->IsMultisampledTexture()); 1321 switch (GetDimension()) { 1322 case wgpu::TextureViewDimension::e2D: 1323 case wgpu::TextureViewDimension::e2DArray: 1324 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY; 1325 uavDesc.Texture2DArray.FirstArraySlice = GetBaseArrayLayer(); 1326 uavDesc.Texture2DArray.ArraySize = GetLayerCount(); 1327 uavDesc.Texture2DArray.MipSlice = GetBaseMipLevel(); 1328 uavDesc.Texture2DArray.PlaneSlice = 0; 1329 break; 1330 case wgpu::TextureViewDimension::e3D: 1331 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D; 1332 uavDesc.Texture3D.FirstWSlice = 0; 1333 uavDesc.Texture3D.WSize = GetTexture()->GetDepth() >> GetBaseMipLevel(); 1334 uavDesc.Texture3D.MipSlice = GetBaseMipLevel(); 1335 break; 1336 // TODO(crbug.com/dawn/814): support 1D textures. 1337 case wgpu::TextureViewDimension::e1D: 1338 // Cube and Cubemap can't be used as storage texture. So there is no need to create UAV 1339 // descriptor for them. 1340 case wgpu::TextureViewDimension::Cube: 1341 case wgpu::TextureViewDimension::CubeArray: 1342 case wgpu::TextureViewDimension::Undefined: 1343 UNREACHABLE(); 1344 } 1345 return uavDesc; 1346 } 1347 1348 }} // namespace dawn_native::d3d12 1349