• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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