• 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/Texture.h"
16 
17 #include <algorithm>
18 
19 #include "common/Assert.h"
20 #include "common/Constants.h"
21 #include "common/Math.h"
22 #include "dawn_native/Adapter.h"
23 #include "dawn_native/ChainUtils_autogen.h"
24 #include "dawn_native/Device.h"
25 #include "dawn_native/EnumMaskIterator.h"
26 #include "dawn_native/ObjectType_autogen.h"
27 #include "dawn_native/PassResourceUsage.h"
28 #include "dawn_native/ValidationUtils_autogen.h"
29 
30 namespace dawn_native {
31     namespace {
32         // WebGPU currently does not have texture format reinterpretation. If it does, the
33         // code to check for it might go here.
ValidateTextureViewFormatCompatibility(const TextureBase * texture,const TextureViewDescriptor * descriptor)34         MaybeError ValidateTextureViewFormatCompatibility(const TextureBase* texture,
35                                                           const TextureViewDescriptor* descriptor) {
36             if (texture->GetFormat().format != descriptor->format) {
37                 if (descriptor->aspect != wgpu::TextureAspect::All &&
38                     texture->GetFormat().GetAspectInfo(descriptor->aspect).format ==
39                         descriptor->format) {
40                     return {};
41                 }
42 
43                 return DAWN_VALIDATION_ERROR(
44                     "The format of texture view is not compatible to the original texture");
45             }
46 
47             return {};
48         }
49 
50         // TODO(crbug.com/dawn/814): Implement for 1D texture.
IsTextureViewDimensionCompatibleWithTextureDimension(wgpu::TextureViewDimension textureViewDimension,wgpu::TextureDimension textureDimension)51         bool IsTextureViewDimensionCompatibleWithTextureDimension(
52             wgpu::TextureViewDimension textureViewDimension,
53             wgpu::TextureDimension textureDimension) {
54             switch (textureViewDimension) {
55                 case wgpu::TextureViewDimension::e2D:
56                 case wgpu::TextureViewDimension::e2DArray:
57                 case wgpu::TextureViewDimension::Cube:
58                 case wgpu::TextureViewDimension::CubeArray:
59                     return textureDimension == wgpu::TextureDimension::e2D;
60 
61                 case wgpu::TextureViewDimension::e3D:
62                     return textureDimension == wgpu::TextureDimension::e3D;
63 
64                 case wgpu::TextureViewDimension::e1D:
65                 case wgpu::TextureViewDimension::Undefined:
66                     break;
67             }
68             UNREACHABLE();
69         }
70 
71         // TODO(crbug.com/dawn/814): Implement for 1D texture.
IsArrayLayerValidForTextureViewDimension(wgpu::TextureViewDimension textureViewDimension,uint32_t textureViewArrayLayer)72         bool IsArrayLayerValidForTextureViewDimension(
73             wgpu::TextureViewDimension textureViewDimension,
74             uint32_t textureViewArrayLayer) {
75             switch (textureViewDimension) {
76                 case wgpu::TextureViewDimension::e2D:
77                 case wgpu::TextureViewDimension::e3D:
78                     return textureViewArrayLayer == 1u;
79                 case wgpu::TextureViewDimension::e2DArray:
80                     return true;
81                 case wgpu::TextureViewDimension::Cube:
82                     return textureViewArrayLayer == 6u;
83                 case wgpu::TextureViewDimension::CubeArray:
84                     return textureViewArrayLayer % 6 == 0;
85 
86                 case wgpu::TextureViewDimension::e1D:
87                 case wgpu::TextureViewDimension::Undefined:
88                     break;
89             }
90             UNREACHABLE();
91         }
92 
ValidateSampleCount(const TextureDescriptor * descriptor,wgpu::TextureUsage usage,const Format * format)93         MaybeError ValidateSampleCount(const TextureDescriptor* descriptor,
94                                        wgpu::TextureUsage usage,
95                                        const Format* format) {
96             DAWN_INVALID_IF(!IsValidSampleCount(descriptor->sampleCount),
97                             "The sample count (%u) of the texture is not supported.",
98                             descriptor->sampleCount);
99 
100             if (descriptor->sampleCount > 1) {
101                 DAWN_INVALID_IF(descriptor->mipLevelCount > 1,
102                                 "The mip level count (%u) of a multisampled texture is not 1.",
103                                 descriptor->mipLevelCount);
104 
105                 // Multisampled 1D and 3D textures are not supported in D3D12/Metal/Vulkan.
106                 // Multisampled 2D array texture is not supported because on Metal it requires the
107                 // version of macOS be greater than 10.14.
108                 DAWN_INVALID_IF(descriptor->dimension != wgpu::TextureDimension::e2D,
109                                 "The dimension (%s) of a multisampled texture is not 2D.",
110                                 descriptor->dimension);
111 
112                 DAWN_INVALID_IF(descriptor->size.depthOrArrayLayers > 1,
113                                 "The depthOrArrayLayers (%u) of a multisampled texture is not 1.",
114                                 descriptor->size.depthOrArrayLayers);
115 
116                 // If a format can support multisample, it must be renderable. Because Vulkan
117                 // requires that if the format is not color-renderable or depth/stencil renderable,
118                 // sampleCount must be 1.
119                 DAWN_INVALID_IF(!format->isRenderable,
120                                 "The texture format (%s) does not support multisampling.",
121                                 format->format);
122 
123                 // Compressed formats are not renderable. They cannot support multisample.
124                 ASSERT(!format->isCompressed);
125 
126                 DAWN_INVALID_IF(usage & wgpu::TextureUsage::StorageBinding,
127                                 "The sample count (%u) of a storage textures is not 1.",
128                                 descriptor->sampleCount);
129             }
130 
131             return {};
132         }
133 
ValidateTextureViewDimensionCompatibility(const TextureBase * texture,const TextureViewDescriptor * descriptor)134         MaybeError ValidateTextureViewDimensionCompatibility(
135             const TextureBase* texture,
136             const TextureViewDescriptor* descriptor) {
137             DAWN_INVALID_IF(
138                 !IsArrayLayerValidForTextureViewDimension(descriptor->dimension,
139                                                           descriptor->arrayLayerCount),
140                 "The dimension (%s) of the texture view is not compatible with the layer count "
141                 "(%u) of %s.",
142                 descriptor->dimension, descriptor->arrayLayerCount, texture);
143 
144             DAWN_INVALID_IF(
145                 !IsTextureViewDimensionCompatibleWithTextureDimension(descriptor->dimension,
146                                                                       texture->GetDimension()),
147                 "The dimension (%s) of the texture view is not compatible with the dimension (%s) "
148                 "of %s.",
149                 descriptor->dimension, texture->GetDimension(), texture);
150 
151             switch (descriptor->dimension) {
152                 case wgpu::TextureViewDimension::Cube:
153                 case wgpu::TextureViewDimension::CubeArray:
154                     DAWN_INVALID_IF(
155                         texture->GetSize().width != texture->GetSize().height,
156                         "A %s texture view is not compatible with %s because the texture's width "
157                         "(%u) and height (%u) are not equal.",
158                         descriptor->dimension, texture, texture->GetSize().width,
159                         texture->GetSize().height);
160                     break;
161 
162                 case wgpu::TextureViewDimension::e2D:
163                 case wgpu::TextureViewDimension::e2DArray:
164                 case wgpu::TextureViewDimension::e3D:
165                     break;
166 
167                 case wgpu::TextureViewDimension::e1D:
168                 case wgpu::TextureViewDimension::Undefined:
169                     UNREACHABLE();
170                     break;
171             }
172 
173             return {};
174         }
175 
ValidateTextureSize(const DeviceBase * device,const TextureDescriptor * descriptor,const Format * format)176         MaybeError ValidateTextureSize(const DeviceBase* device,
177                                        const TextureDescriptor* descriptor,
178                                        const Format* format) {
179             ASSERT(descriptor->size.width != 0 && descriptor->size.height != 0 &&
180                    descriptor->size.depthOrArrayLayers != 0);
181             const CombinedLimits& limits = device->GetLimits();
182             Extent3D maxExtent;
183             switch (descriptor->dimension) {
184                 case wgpu::TextureDimension::e2D:
185                     maxExtent = {limits.v1.maxTextureDimension2D, limits.v1.maxTextureDimension2D,
186                                  limits.v1.maxTextureArrayLayers};
187                     break;
188                 case wgpu::TextureDimension::e3D:
189                     maxExtent = {limits.v1.maxTextureDimension3D, limits.v1.maxTextureDimension3D,
190                                  limits.v1.maxTextureDimension3D};
191                     break;
192                 case wgpu::TextureDimension::e1D:
193                 default:
194                     UNREACHABLE();
195             }
196             DAWN_INVALID_IF(descriptor->size.width > maxExtent.width ||
197                                 descriptor->size.height > maxExtent.height ||
198                                 descriptor->size.depthOrArrayLayers > maxExtent.depthOrArrayLayers,
199                             "Texture size (%s) exceeded maximum texture size (%s).",
200                             &descriptor->size, &maxExtent);
201 
202             uint32_t maxMippedDimension = descriptor->size.width;
203             if (descriptor->dimension != wgpu::TextureDimension::e1D) {
204                 maxMippedDimension = std::max(maxMippedDimension, descriptor->size.height);
205             }
206             if (descriptor->dimension == wgpu::TextureDimension::e3D) {
207                 maxMippedDimension =
208                     std::max(maxMippedDimension, descriptor->size.depthOrArrayLayers);
209             }
210             DAWN_INVALID_IF(
211                 Log2(maxMippedDimension) + 1 < descriptor->mipLevelCount,
212                 "Texture mip level count (%u) exceeds the maximum (%u) for its size (%s).",
213                 descriptor->mipLevelCount, Log2(maxMippedDimension) + 1, &descriptor->size);
214 
215             if (format->isCompressed) {
216                 const TexelBlockInfo& blockInfo =
217                     format->GetAspectInfo(wgpu::TextureAspect::All).block;
218                 DAWN_INVALID_IF(
219                     descriptor->size.width % blockInfo.width != 0 ||
220                         descriptor->size.height % blockInfo.height != 0,
221                     "The size (%s) of the texture is not a multiple of the block width (%u) and "
222                     "height (%u) of the texture format (%s).",
223                     &descriptor->size, blockInfo.width, blockInfo.height, format->format);
224             }
225 
226             return {};
227         }
228 
ValidateTextureUsage(const TextureDescriptor * descriptor,wgpu::TextureUsage usage,const Format * format)229         MaybeError ValidateTextureUsage(const TextureDescriptor* descriptor,
230                                         wgpu::TextureUsage usage,
231                                         const Format* format) {
232             DAWN_TRY(dawn_native::ValidateTextureUsage(usage));
233 
234             constexpr wgpu::TextureUsage kValidCompressedUsages =
235                 wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc |
236                 wgpu::TextureUsage::CopyDst;
237             DAWN_INVALID_IF(
238                 format->isCompressed && !IsSubset(usage, kValidCompressedUsages),
239                 "The texture usage (%s) is incompatible with the compressed texture format (%s).",
240                 usage, format->format);
241 
242             DAWN_INVALID_IF(
243                 !format->isRenderable && (usage & wgpu::TextureUsage::RenderAttachment),
244                 "The texture usage (%s) includes %s, which is incompatible with the non-renderable "
245                 "format (%s).",
246                 usage, wgpu::TextureUsage::RenderAttachment, format->format);
247 
248             DAWN_INVALID_IF(
249                 !format->supportsStorageUsage && (usage & wgpu::TextureUsage::StorageBinding),
250                 "The texture usage (%s) includes %s, which is incompatible with the format (%s).",
251                 usage, wgpu::TextureUsage::StorageBinding, format->format);
252 
253             constexpr wgpu::TextureUsage kValidMultiPlanarUsages =
254                 wgpu::TextureUsage::TextureBinding;
255             DAWN_INVALID_IF(
256                 format->IsMultiPlanar() && !IsSubset(usage, kValidMultiPlanarUsages),
257                 "The texture usage (%s) is incompatible with the multi-planar format (%s).", usage,
258                 format->format);
259 
260             return {};
261         }
262 
263     }  // anonymous namespace
264 
ValidateTextureDescriptor(const DeviceBase * device,const TextureDescriptor * descriptor)265     MaybeError ValidateTextureDescriptor(const DeviceBase* device,
266                                          const TextureDescriptor* descriptor) {
267         DAWN_TRY(ValidateSingleSType(descriptor->nextInChain,
268                                      wgpu::SType::DawnTextureInternalUsageDescriptor));
269 
270         const DawnTextureInternalUsageDescriptor* internalUsageDesc = nullptr;
271         FindInChain(descriptor->nextInChain, &internalUsageDesc);
272 
273         DAWN_INVALID_IF(descriptor->dimension == wgpu::TextureDimension::e1D,
274                         "1D textures aren't supported (yet).");
275 
276         DAWN_INVALID_IF(
277             internalUsageDesc != nullptr && !device->IsFeatureEnabled(Feature::DawnInternalUsages),
278             "The dawn-internal-usages feature is not enabled");
279 
280         const Format* format;
281         DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->format));
282 
283         wgpu::TextureUsage usage = descriptor->usage;
284         if (internalUsageDesc != nullptr) {
285             usage |= internalUsageDesc->internalUsage;
286         }
287 
288         DAWN_TRY(ValidateTextureUsage(descriptor, usage, format));
289         DAWN_TRY(ValidateTextureDimension(descriptor->dimension));
290         DAWN_TRY(ValidateSampleCount(descriptor, usage, format));
291 
292         DAWN_INVALID_IF(descriptor->size.width == 0 || descriptor->size.height == 0 ||
293                             descriptor->size.depthOrArrayLayers == 0 ||
294                             descriptor->mipLevelCount == 0,
295                         "The texture size (%s) or mipLevelCount (%u) is empty.", &descriptor->size,
296                         descriptor->mipLevelCount);
297 
298         DAWN_INVALID_IF(
299             descriptor->dimension != wgpu::TextureDimension::e2D && format->isCompressed,
300             "The dimension (%s) of a texture with a compressed format (%s) is not 2D.",
301             descriptor->dimension, format->format);
302 
303         // Depth/stencil formats are valid for 2D textures only. Metal has this limit. And D3D12
304         // doesn't support depth/stencil formats on 3D textures.
305         DAWN_INVALID_IF(
306             descriptor->dimension != wgpu::TextureDimension::e2D &&
307                 (format->aspects & (Aspect::Depth | Aspect::Stencil)) != 0,
308             "The dimension (%s) of a texture with a depth/stencil format (%s) is not 2D.",
309             descriptor->dimension, format->format);
310 
311         DAWN_TRY(ValidateTextureSize(device, descriptor, format));
312 
313         // TODO(crbug.com/dawn/838): Implement a workaround for this issue.
314         // Readbacks from the non-zero mip of a stencil texture may contain garbage data.
315         DAWN_INVALID_IF(
316             device->IsToggleEnabled(Toggle::DisallowUnsafeAPIs) && format->HasStencil() &&
317                 descriptor->mipLevelCount > 1 &&
318                 device->GetAdapter()->GetBackendType() == wgpu::BackendType::Metal,
319             "https://crbug.com/dawn/838: Stencil textures with more than one mip level are "
320             "disabled on Metal.");
321 
322         DAWN_INVALID_IF(
323             device->IsToggleEnabled(Toggle::DisableR8RG8Mipmaps) && descriptor->mipLevelCount > 1 &&
324                 (descriptor->format == wgpu::TextureFormat::R8Unorm ||
325                  descriptor->format == wgpu::TextureFormat::RG8Unorm),
326             "https://crbug.com/dawn/1071: r8unorm and rg8unorm textures with more than one mip "
327             "level are disabled on Metal.");
328 
329         return {};
330     }
331 
ValidateTextureViewDescriptor(const DeviceBase * device,const TextureBase * texture,const TextureViewDescriptor * descriptor)332     MaybeError ValidateTextureViewDescriptor(const DeviceBase* device,
333                                              const TextureBase* texture,
334                                              const TextureViewDescriptor* descriptor) {
335         DAWN_INVALID_IF(descriptor->nextInChain != nullptr, "nextInChain must be nullptr.");
336 
337         // Parent texture should have been already validated.
338         ASSERT(texture);
339         ASSERT(!texture->IsError());
340 
341         DAWN_TRY(ValidateTextureViewDimension(descriptor->dimension));
342         DAWN_INVALID_IF(descriptor->dimension == wgpu::TextureViewDimension::e1D,
343                         "1D texture views aren't supported (yet).");
344 
345         DAWN_TRY(ValidateTextureFormat(descriptor->format));
346 
347         DAWN_TRY(ValidateTextureAspect(descriptor->aspect));
348         DAWN_INVALID_IF(
349             SelectFormatAspects(texture->GetFormat(), descriptor->aspect) == Aspect::None,
350             "Texture format (%s) does not have the texture view's selected aspect (%s).",
351             texture->GetFormat().format, descriptor->aspect);
352 
353         DAWN_INVALID_IF(descriptor->arrayLayerCount == 0 || descriptor->mipLevelCount == 0,
354                         "The texture view's arrayLayerCount (%u) or mipLevelCount (%u) is zero.",
355                         descriptor->arrayLayerCount, descriptor->mipLevelCount);
356 
357         DAWN_INVALID_IF(
358             uint64_t(descriptor->baseArrayLayer) + uint64_t(descriptor->arrayLayerCount) >
359                 uint64_t(texture->GetArrayLayers()),
360             "Texture view array layer range (baseArrayLayer: %u, arrayLayerCount: %u) exceeds the "
361             "texture's array layer count (%u).",
362             descriptor->baseArrayLayer, descriptor->arrayLayerCount, texture->GetArrayLayers());
363 
364         DAWN_INVALID_IF(
365             uint64_t(descriptor->baseMipLevel) + uint64_t(descriptor->mipLevelCount) >
366                 uint64_t(texture->GetNumMipLevels()),
367             "Texture view mip level range (baseMipLevel: %u, mipLevelCount: %u) exceeds the "
368             "texture's mip level count (%u).",
369             descriptor->baseMipLevel, descriptor->mipLevelCount, texture->GetNumMipLevels());
370 
371         DAWN_TRY(ValidateTextureViewFormatCompatibility(texture, descriptor));
372         DAWN_TRY(ValidateTextureViewDimensionCompatibility(texture, descriptor));
373 
374         return {};
375     }
376 
GetTextureViewDescriptorWithDefaults(const TextureBase * texture,const TextureViewDescriptor * descriptor)377     TextureViewDescriptor GetTextureViewDescriptorWithDefaults(
378         const TextureBase* texture,
379         const TextureViewDescriptor* descriptor) {
380         ASSERT(texture);
381 
382         TextureViewDescriptor desc = {};
383         if (descriptor) {
384             desc = *descriptor;
385         }
386 
387         // The default value for the view dimension depends on the texture's dimension with a
388         // special case for 2DArray being chosen automatically if arrayLayerCount is unspecified.
389         if (desc.dimension == wgpu::TextureViewDimension::Undefined) {
390             switch (texture->GetDimension()) {
391                 case wgpu::TextureDimension::e1D:
392                     desc.dimension = wgpu::TextureViewDimension::e1D;
393                     break;
394 
395                 case wgpu::TextureDimension::e2D:
396                     desc.dimension = wgpu::TextureViewDimension::e2D;
397                     break;
398 
399                 case wgpu::TextureDimension::e3D:
400                     desc.dimension = wgpu::TextureViewDimension::e3D;
401                     break;
402             }
403         }
404 
405         if (desc.format == wgpu::TextureFormat::Undefined) {
406             // TODO(dawn:682): Use GetAspectInfo(aspect).
407             desc.format = texture->GetFormat().format;
408         }
409         if (desc.arrayLayerCount == wgpu::kArrayLayerCountUndefined) {
410             switch (desc.dimension) {
411                 case wgpu::TextureViewDimension::e1D:
412                 case wgpu::TextureViewDimension::e2D:
413                 case wgpu::TextureViewDimension::e3D:
414                     desc.arrayLayerCount = 1;
415                     break;
416                 case wgpu::TextureViewDimension::Cube:
417                     desc.arrayLayerCount = 6;
418                     break;
419                 case wgpu::TextureViewDimension::e2DArray:
420                 case wgpu::TextureViewDimension::CubeArray:
421                     desc.arrayLayerCount = texture->GetArrayLayers() - desc.baseArrayLayer;
422                     break;
423                 default:
424                     // We don't put UNREACHABLE() here because we validate enums only after this
425                     // function sets default values. Otherwise, the UNREACHABLE() will be hit.
426                     break;
427             }
428         }
429 
430         if (desc.mipLevelCount == wgpu::kMipLevelCountUndefined) {
431             desc.mipLevelCount = texture->GetNumMipLevels() - desc.baseMipLevel;
432         }
433         return desc;
434     }
435 
436     // WebGPU only supports sample counts of 1 and 4. We could expand to more based on
437     // platform support, but it would probably be a feature.
IsValidSampleCount(uint32_t sampleCount)438     bool IsValidSampleCount(uint32_t sampleCount) {
439         switch (sampleCount) {
440             case 1:
441             case 4:
442                 return true;
443 
444             default:
445                 return false;
446         }
447     }
448 
449     // TextureBase
450 
TextureBase(DeviceBase * device,const TextureDescriptor * descriptor,TextureState state)451     TextureBase::TextureBase(DeviceBase* device,
452                              const TextureDescriptor* descriptor,
453                              TextureState state)
454         : ApiObjectBase(device, descriptor->label),
455           mDimension(descriptor->dimension),
456           mFormat(device->GetValidInternalFormat(descriptor->format)),
457           mSize(descriptor->size),
458           mMipLevelCount(descriptor->mipLevelCount),
459           mSampleCount(descriptor->sampleCount),
460           mUsage(descriptor->usage),
461           mInternalUsage(mUsage),
462           mState(state) {
463         uint32_t subresourceCount =
464             mMipLevelCount * GetArrayLayers() * GetAspectCount(mFormat.aspects);
465         mIsSubresourceContentInitializedAtIndex = std::vector<bool>(subresourceCount, false);
466 
467         const DawnTextureInternalUsageDescriptor* internalUsageDesc = nullptr;
468         FindInChain(descriptor->nextInChain, &internalUsageDesc);
469         if (internalUsageDesc != nullptr) {
470             mInternalUsage |= internalUsageDesc->internalUsage;
471         }
472         TrackInDevice();
473     }
474 
475     static Format kUnusedFormat;
476 
TextureBase(DeviceBase * device,TextureState state)477     TextureBase::TextureBase(DeviceBase* device, TextureState state)
478         : ApiObjectBase(device, kLabelNotImplemented), mFormat(kUnusedFormat), mState(state) {
479         TrackInDevice();
480     }
481 
TextureBase(DeviceBase * device,ObjectBase::ErrorTag tag)482     TextureBase::TextureBase(DeviceBase* device, ObjectBase::ErrorTag tag)
483         : ApiObjectBase(device, tag), mFormat(kUnusedFormat) {
484     }
485 
DestroyImpl()486     void TextureBase::DestroyImpl() {
487         mState = TextureState::Destroyed;
488     }
489 
490     // static
MakeError(DeviceBase * device)491     TextureBase* TextureBase::MakeError(DeviceBase* device) {
492         return new TextureBase(device, ObjectBase::kError);
493     }
494 
GetType() const495     ObjectType TextureBase::GetType() const {
496         return ObjectType::Texture;
497     }
498 
GetDimension() const499     wgpu::TextureDimension TextureBase::GetDimension() const {
500         ASSERT(!IsError());
501         return mDimension;
502     }
503 
GetFormat() const504     const Format& TextureBase::GetFormat() const {
505         ASSERT(!IsError());
506         return mFormat;
507     }
GetSize() const508     const Extent3D& TextureBase::GetSize() const {
509         ASSERT(!IsError());
510         return mSize;
511     }
GetWidth() const512     uint32_t TextureBase::GetWidth() const {
513         ASSERT(!IsError());
514         return mSize.width;
515     }
GetHeight() const516     uint32_t TextureBase::GetHeight() const {
517         ASSERT(!IsError());
518         ASSERT(mDimension != wgpu::TextureDimension::e1D);
519         return mSize.height;
520     }
GetDepth() const521     uint32_t TextureBase::GetDepth() const {
522         ASSERT(!IsError());
523         ASSERT(mDimension == wgpu::TextureDimension::e3D);
524         return mSize.depthOrArrayLayers;
525     }
GetArrayLayers() const526     uint32_t TextureBase::GetArrayLayers() const {
527         ASSERT(!IsError());
528         // TODO(crbug.com/dawn/814): Update for 1D textures when they are supported.
529         ASSERT(mDimension != wgpu::TextureDimension::e1D);
530         if (mDimension == wgpu::TextureDimension::e3D) {
531             return 1;
532         }
533         return mSize.depthOrArrayLayers;
534     }
GetNumMipLevels() const535     uint32_t TextureBase::GetNumMipLevels() const {
536         ASSERT(!IsError());
537         return mMipLevelCount;
538     }
GetAllSubresources() const539     SubresourceRange TextureBase::GetAllSubresources() const {
540         ASSERT(!IsError());
541         return {mFormat.aspects, {0, GetArrayLayers()}, {0, mMipLevelCount}};
542     }
GetSampleCount() const543     uint32_t TextureBase::GetSampleCount() const {
544         ASSERT(!IsError());
545         return mSampleCount;
546     }
GetSubresourceCount() const547     uint32_t TextureBase::GetSubresourceCount() const {
548         ASSERT(!IsError());
549         return static_cast<uint32_t>(mIsSubresourceContentInitializedAtIndex.size());
550     }
GetUsage() const551     wgpu::TextureUsage TextureBase::GetUsage() const {
552         ASSERT(!IsError());
553         return mUsage;
554     }
GetInternalUsage() const555     wgpu::TextureUsage TextureBase::GetInternalUsage() const {
556         ASSERT(!IsError());
557         return mInternalUsage;
558     }
559 
GetTextureState() const560     TextureBase::TextureState TextureBase::GetTextureState() const {
561         ASSERT(!IsError());
562         return mState;
563     }
564 
GetSubresourceIndex(uint32_t mipLevel,uint32_t arraySlice,Aspect aspect) const565     uint32_t TextureBase::GetSubresourceIndex(uint32_t mipLevel,
566                                               uint32_t arraySlice,
567                                               Aspect aspect) const {
568         ASSERT(HasOneBit(aspect));
569         return mipLevel +
570                GetNumMipLevels() * (arraySlice + GetArrayLayers() * GetAspectIndex(aspect));
571     }
572 
IsSubresourceContentInitialized(const SubresourceRange & range) const573     bool TextureBase::IsSubresourceContentInitialized(const SubresourceRange& range) const {
574         ASSERT(!IsError());
575         for (Aspect aspect : IterateEnumMask(range.aspects)) {
576             for (uint32_t arrayLayer = range.baseArrayLayer;
577                  arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) {
578                 for (uint32_t mipLevel = range.baseMipLevel;
579                      mipLevel < range.baseMipLevel + range.levelCount; ++mipLevel) {
580                     uint32_t subresourceIndex = GetSubresourceIndex(mipLevel, arrayLayer, aspect);
581                     ASSERT(subresourceIndex < mIsSubresourceContentInitializedAtIndex.size());
582                     if (!mIsSubresourceContentInitializedAtIndex[subresourceIndex]) {
583                         return false;
584                     }
585                 }
586             }
587         }
588         return true;
589     }
590 
SetIsSubresourceContentInitialized(bool isInitialized,const SubresourceRange & range)591     void TextureBase::SetIsSubresourceContentInitialized(bool isInitialized,
592                                                          const SubresourceRange& range) {
593         ASSERT(!IsError());
594         for (Aspect aspect : IterateEnumMask(range.aspects)) {
595             for (uint32_t arrayLayer = range.baseArrayLayer;
596                  arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) {
597                 for (uint32_t mipLevel = range.baseMipLevel;
598                      mipLevel < range.baseMipLevel + range.levelCount; ++mipLevel) {
599                     uint32_t subresourceIndex = GetSubresourceIndex(mipLevel, arrayLayer, aspect);
600                     ASSERT(subresourceIndex < mIsSubresourceContentInitializedAtIndex.size());
601                     mIsSubresourceContentInitializedAtIndex[subresourceIndex] = isInitialized;
602                 }
603             }
604         }
605     }
606 
ValidateCanUseInSubmitNow() const607     MaybeError TextureBase::ValidateCanUseInSubmitNow() const {
608         ASSERT(!IsError());
609         DAWN_INVALID_IF(mState == TextureState::Destroyed, "Destroyed texture %s used in a submit.",
610                         this);
611         return {};
612     }
613 
IsMultisampledTexture() const614     bool TextureBase::IsMultisampledTexture() const {
615         ASSERT(!IsError());
616         return mSampleCount > 1;
617     }
618 
GetMipLevelVirtualSize(uint32_t level) const619     Extent3D TextureBase::GetMipLevelVirtualSize(uint32_t level) const {
620         Extent3D extent = {std::max(mSize.width >> level, 1u), 1u, 1u};
621         if (mDimension == wgpu::TextureDimension::e1D) {
622             return extent;
623         }
624 
625         extent.height = std::max(mSize.height >> level, 1u);
626         if (mDimension == wgpu::TextureDimension::e2D) {
627             return extent;
628         }
629 
630         extent.depthOrArrayLayers = std::max(mSize.depthOrArrayLayers >> level, 1u);
631         return extent;
632     }
633 
GetMipLevelPhysicalSize(uint32_t level) const634     Extent3D TextureBase::GetMipLevelPhysicalSize(uint32_t level) const {
635         Extent3D extent = GetMipLevelVirtualSize(level);
636 
637         // Compressed Textures will have paddings if their width or height is not a multiple of
638         // 4 at non-zero mipmap levels.
639         if (mFormat.isCompressed && level != 0) {
640             // If |level| is non-zero, then each dimension of |extent| is at most half of
641             // the max texture dimension. Computations here which add the block width/height
642             // to the extent cannot overflow.
643             const TexelBlockInfo& blockInfo = mFormat.GetAspectInfo(wgpu::TextureAspect::All).block;
644             extent.width = (extent.width + blockInfo.width - 1) / blockInfo.width * blockInfo.width;
645             extent.height =
646                 (extent.height + blockInfo.height - 1) / blockInfo.height * blockInfo.height;
647         }
648 
649         return extent;
650     }
651 
ClampToMipLevelVirtualSize(uint32_t level,const Origin3D & origin,const Extent3D & extent) const652     Extent3D TextureBase::ClampToMipLevelVirtualSize(uint32_t level,
653                                                      const Origin3D& origin,
654                                                      const Extent3D& extent) const {
655         const Extent3D virtualSizeAtLevel = GetMipLevelVirtualSize(level);
656         ASSERT(origin.x <= virtualSizeAtLevel.width);
657         ASSERT(origin.y <= virtualSizeAtLevel.height);
658         uint32_t clampedCopyExtentWidth = (extent.width > virtualSizeAtLevel.width - origin.x)
659                                               ? (virtualSizeAtLevel.width - origin.x)
660                                               : extent.width;
661         uint32_t clampedCopyExtentHeight = (extent.height > virtualSizeAtLevel.height - origin.y)
662                                                ? (virtualSizeAtLevel.height - origin.y)
663                                                : extent.height;
664         return {clampedCopyExtentWidth, clampedCopyExtentHeight, extent.depthOrArrayLayers};
665     }
666 
APICreateView(const TextureViewDescriptor * descriptor)667     TextureViewBase* TextureBase::APICreateView(const TextureViewDescriptor* descriptor) {
668         DeviceBase* device = GetDevice();
669 
670         Ref<TextureViewBase> result;
671         if (device->ConsumedError(device->CreateTextureView(this, descriptor), &result,
672                                   "calling %s.CreateView(%s).", this, descriptor)) {
673             return TextureViewBase::MakeError(device);
674         }
675         return result.Detach();
676     }
677 
APIDestroy()678     void TextureBase::APIDestroy() {
679         if (GetDevice()->ConsumedError(ValidateDestroy(), "calling %s.Destroy().", this)) {
680             return;
681         }
682         ASSERT(!IsError());
683         Destroy();
684     }
685 
ValidateDestroy() const686     MaybeError TextureBase::ValidateDestroy() const {
687         DAWN_TRY(GetDevice()->ValidateObject(this));
688         return {};
689     }
690 
691     // TextureViewBase
692 
TextureViewBase(TextureBase * texture,const TextureViewDescriptor * descriptor)693     TextureViewBase::TextureViewBase(TextureBase* texture, const TextureViewDescriptor* descriptor)
694         : ApiObjectBase(texture->GetDevice(), descriptor->label),
695           mTexture(texture),
696           mFormat(GetDevice()->GetValidInternalFormat(descriptor->format)),
697           mDimension(descriptor->dimension),
698           mRange({ConvertViewAspect(mFormat, descriptor->aspect),
699                   {descriptor->baseArrayLayer, descriptor->arrayLayerCount},
700                   {descriptor->baseMipLevel, descriptor->mipLevelCount}}) {
701         TrackInDevice();
702     }
703 
TextureViewBase(TextureBase * texture)704     TextureViewBase::TextureViewBase(TextureBase* texture)
705         : ApiObjectBase(texture->GetDevice(), kLabelNotImplemented),
706           mTexture(texture),
707           mFormat(kUnusedFormat) {
708         TrackInDevice();
709     }
710 
TextureViewBase(DeviceBase * device,ObjectBase::ErrorTag tag)711     TextureViewBase::TextureViewBase(DeviceBase* device, ObjectBase::ErrorTag tag)
712         : ApiObjectBase(device, tag), mFormat(kUnusedFormat) {
713     }
714 
DestroyImpl()715     void TextureViewBase::DestroyImpl() {
716     }
717 
718     // static
MakeError(DeviceBase * device)719     TextureViewBase* TextureViewBase::MakeError(DeviceBase* device) {
720         return new TextureViewBase(device, ObjectBase::kError);
721     }
722 
GetType() const723     ObjectType TextureViewBase::GetType() const {
724         return ObjectType::TextureView;
725     }
726 
GetTexture() const727     const TextureBase* TextureViewBase::GetTexture() const {
728         ASSERT(!IsError());
729         return mTexture.Get();
730     }
731 
GetTexture()732     TextureBase* TextureViewBase::GetTexture() {
733         ASSERT(!IsError());
734         return mTexture.Get();
735     }
736 
GetAspects() const737     Aspect TextureViewBase::GetAspects() const {
738         ASSERT(!IsError());
739         return mRange.aspects;
740     }
741 
GetFormat() const742     const Format& TextureViewBase::GetFormat() const {
743         ASSERT(!IsError());
744         return mFormat;
745     }
746 
GetDimension() const747     wgpu::TextureViewDimension TextureViewBase::GetDimension() const {
748         ASSERT(!IsError());
749         return mDimension;
750     }
751 
GetBaseMipLevel() const752     uint32_t TextureViewBase::GetBaseMipLevel() const {
753         ASSERT(!IsError());
754         return mRange.baseMipLevel;
755     }
756 
GetLevelCount() const757     uint32_t TextureViewBase::GetLevelCount() const {
758         ASSERT(!IsError());
759         return mRange.levelCount;
760     }
761 
GetBaseArrayLayer() const762     uint32_t TextureViewBase::GetBaseArrayLayer() const {
763         ASSERT(!IsError());
764         return mRange.baseArrayLayer;
765     }
766 
GetLayerCount() const767     uint32_t TextureViewBase::GetLayerCount() const {
768         ASSERT(!IsError());
769         return mRange.layerCount;
770     }
771 
GetSubresourceRange() const772     const SubresourceRange& TextureViewBase::GetSubresourceRange() const {
773         ASSERT(!IsError());
774         return mRange;
775     }
776 
777 }  // namespace dawn_native
778