Add internal usage for copyTextureForBrowser

Add an internal usage option for copyTextureForBrowserOption
allowing internal calls from call to use canvas context
texture as source/destination.

Bug: chromium:1331139
Change-Id: Ida8421b3962a6434e8ef57c581c7a2e1d607954c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94985
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Shrek Shao <shrekshao@google.com>
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/dawn.json b/dawn.json
index ec3cb28..1fa746a 100644
--- a/dawn.json
+++ b/dawn.json
@@ -922,7 +922,8 @@
                      "length": 9, "optional": true},
             {"name": "dst transfer function parameters", "type": "float", "annotation": "const*",
                      "length": 7, "optional": true},
-            {"name": "dst alpha mode", "type": "alpha mode", "default": "unpremultiplied"}
+            {"name": "dst alpha mode", "type": "alpha mode", "default": "unpremultiplied"},
+            {"name": "internal usage", "type": "bool", "default": "false"}
         ]
     },
     "create compute pipeline async callback": {
diff --git a/src/dawn/native/BUILD.gn b/src/dawn/native/BUILD.gn
index 81110b5..e6cbc4d 100644
--- a/src/dawn/native/BUILD.gn
+++ b/src/dawn/native/BUILD.gn
@@ -330,6 +330,7 @@
     "ToBackend.h",
     "Toggles.cpp",
     "Toggles.h",
+    "UsageValidationMode.h",
     "VertexFormat.cpp",
     "VertexFormat.h",
     "dawn_platform.h",
diff --git a/src/dawn/native/BindGroup.cpp b/src/dawn/native/BindGroup.cpp
index 0d3af77..c5e0afc 100644
--- a/src/dawn/native/BindGroup.cpp
+++ b/src/dawn/native/BindGroup.cpp
@@ -20,12 +20,14 @@
 #include "dawn/native/BindGroupLayout.h"
 #include "dawn/native/Buffer.h"
 #include "dawn/native/ChainUtils_autogen.h"
+#include "dawn/native/CommandValidation.h"
 #include "dawn/native/Device.h"
 #include "dawn/native/ExternalTexture.h"
 #include "dawn/native/ObjectBase.h"
 #include "dawn/native/ObjectType_autogen.h"
 #include "dawn/native/Sampler.h"
 #include "dawn/native/Texture.h"
+#include "dawn/native/utils/WGPUHelpers.h"
 
 namespace dawn::native {
 
@@ -114,7 +116,8 @@
 
 MaybeError ValidateTextureBinding(DeviceBase* device,
                                   const BindGroupEntry& entry,
-                                  const BindingInfo& bindingInfo) {
+                                  const BindingInfo& bindingInfo,
+                                  UsageValidationMode mode) {
     DAWN_INVALID_IF(entry.textureView == nullptr, "Binding entry textureView not set.");
 
     DAWN_INVALID_IF(entry.sampler != nullptr || entry.buffer != nullptr,
@@ -136,9 +139,7 @@
                 texture->GetFormat().GetAspectInfo(aspect).supportedSampleTypes;
             SampleTypeBit requiredType = SampleTypeToSampleTypeBit(bindingInfo.texture.sampleType);
 
-            DAWN_INVALID_IF(!(texture->GetUsage() & wgpu::TextureUsage::TextureBinding),
-                            "Usage (%s) of %s doesn't include TextureUsage::TextureBinding.",
-                            texture->GetUsage(), texture);
+            DAWN_TRY(ValidateCanUseAs(texture, wgpu::TextureUsage::TextureBinding, mode));
 
             DAWN_INVALID_IF(texture->IsMultisampledTexture() != bindingInfo.texture.multisampled,
                             "Sample count (%u) of %s doesn't match expectation (multisampled: %d).",
@@ -157,9 +158,7 @@
             break;
         }
         case BindingInfoType::StorageTexture: {
-            DAWN_INVALID_IF(!(texture->GetUsage() & wgpu::TextureUsage::StorageBinding),
-                            "Usage (%s) of %s doesn't include TextureUsage::StorageBinding.",
-                            texture->GetUsage(), texture);
+            DAWN_TRY(ValidateCanUseAs(texture, wgpu::TextureUsage::StorageBinding, mode));
 
             ASSERT(!texture->IsMultisampledTexture());
 
@@ -253,7 +252,9 @@
 
 }  // anonymous namespace
 
-MaybeError ValidateBindGroupDescriptor(DeviceBase* device, const BindGroupDescriptor* descriptor) {
+MaybeError ValidateBindGroupDescriptor(DeviceBase* device,
+                                       const BindGroupDescriptor* descriptor,
+                                       UsageValidationMode mode) {
     DAWN_INVALID_IF(descriptor->nextInChain != nullptr, "nextInChain must be nullptr.");
 
     DAWN_TRY(device->ValidateObject(descriptor->layout));
@@ -314,6 +315,7 @@
         // Perform binding-type specific validation.
         switch (bindingInfo.bindingType) {
             case BindingInfoType::Buffer:
+                // TODO(dawn:1485): Validate buffer binding with usage validation mode.
                 DAWN_TRY_CONTEXT(ValidateBufferBinding(device, entry, bindingInfo),
                                  "validating entries[%u] as a Buffer."
                                  "\nExpected entry layout: %s",
@@ -321,7 +323,7 @@
                 break;
             case BindingInfoType::Texture:
             case BindingInfoType::StorageTexture:
-                DAWN_TRY_CONTEXT(ValidateTextureBinding(device, entry, bindingInfo),
+                DAWN_TRY_CONTEXT(ValidateTextureBinding(device, entry, bindingInfo, mode),
                                  "validating entries[%u] as a Texture."
                                  "\nExpected entry layout: %s",
                                  i, bindingInfo);
diff --git a/src/dawn/native/BindGroup.h b/src/dawn/native/BindGroup.h
index 236e4fb..34c122b 100644
--- a/src/dawn/native/BindGroup.h
+++ b/src/dawn/native/BindGroup.h
@@ -24,6 +24,7 @@
 #include "dawn/native/Error.h"
 #include "dawn/native/Forward.h"
 #include "dawn/native/ObjectBase.h"
+#include "dawn/native/UsageValidationMode.h"
 
 #include "dawn/native/dawn_platform.h"
 
@@ -31,7 +32,9 @@
 
 class DeviceBase;
 
-MaybeError ValidateBindGroupDescriptor(DeviceBase* device, const BindGroupDescriptor* descriptor);
+MaybeError ValidateBindGroupDescriptor(DeviceBase* device,
+                                       const BindGroupDescriptor* descriptor,
+                                       UsageValidationMode mode);
 
 struct BufferBinding {
     BufferBase* buffer;
diff --git a/src/dawn/native/CMakeLists.txt b/src/dawn/native/CMakeLists.txt
index 9eecfc5..9cf3b68 100644
--- a/src/dawn/native/CMakeLists.txt
+++ b/src/dawn/native/CMakeLists.txt
@@ -187,6 +187,7 @@
     "ToBackend.h"
     "Toggles.cpp"
     "Toggles.h"
+    "UsageValidationMode.h"
     "VertexFormat.cpp"
     "VertexFormat.h"
     "dawn_platform.h"
diff --git a/src/dawn/native/CommandValidation.cpp b/src/dawn/native/CommandValidation.cpp
index 723f658..d0bdb0c 100644
--- a/src/dawn/native/CommandValidation.cpp
+++ b/src/dawn/native/CommandValidation.cpp
@@ -471,7 +471,6 @@
                             texture->GetInternalUsage(), usage);
             break;
     }
-
     return {};
 }
 
diff --git a/src/dawn/native/CommandValidation.h b/src/dawn/native/CommandValidation.h
index ede6b31..bf4e8aa 100644
--- a/src/dawn/native/CommandValidation.h
+++ b/src/dawn/native/CommandValidation.h
@@ -20,6 +20,7 @@
 #include "dawn/native/CommandAllocator.h"
 #include "dawn/native/Error.h"
 #include "dawn/native/Texture.h"
+#include "dawn/native/UsageValidationMode.h"
 
 namespace dawn::native {
 
@@ -82,11 +83,6 @@
                                                     const ImageCopyTexture& dst,
                                                     const Extent3D& copySize);
 
-enum class UsageValidationMode {
-    Default,
-    Internal,
-};
-
 MaybeError ValidateCanUseAs(const TextureBase* texture,
                             wgpu::TextureUsage usage,
                             UsageValidationMode mode);
diff --git a/src/dawn/native/ComputePassEncoder.cpp b/src/dawn/native/ComputePassEncoder.cpp
index a7f9ef5..30fa36b 100644
--- a/src/dawn/native/ComputePassEncoder.cpp
+++ b/src/dawn/native/ComputePassEncoder.cpp
@@ -306,7 +306,8 @@
                                              {1, indirectBuffer, clientIndirectBindingOffset,
                                               clientIndirectBindingSize},
                                              {2, validatedIndirectBuffer, 0, scratchBufferSize},
-                                         }));
+                                         },
+                                         UsageValidationMode::Internal));
 
     // Issue commands to validate the indirect buffer.
     APISetPipeline(validationPipeline.Get());
diff --git a/src/dawn/native/CopyTextureForBrowserHelper.cpp b/src/dawn/native/CopyTextureForBrowserHelper.cpp
index 48cf6e6..112eb0f 100644
--- a/src/dawn/native/CopyTextureForBrowserHelper.cpp
+++ b/src/dawn/native/CopyTextureForBrowserHelper.cpp
@@ -354,15 +354,15 @@
         "not 1.",
         source->texture->GetSampleCount(), destination->texture->GetSampleCount());
 
-    DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc,
-                              UsageValidationMode::Default));
-    DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::TextureBinding,
-                              UsageValidationMode::Default));
-
-    DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst,
-                              UsageValidationMode::Default));
-    DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::RenderAttachment,
-                              UsageValidationMode::Default));
+    DAWN_INVALID_IF(
+        options->internalUsage && !device->IsFeatureEnabled(Feature::DawnInternalUsages),
+        "The internalUsage is true while the dawn-internal-usages feature is not enabled.");
+    UsageValidationMode mode =
+        options->internalUsage ? UsageValidationMode::Internal : UsageValidationMode::Default;
+    DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc, mode));
+    DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::TextureBinding, mode));
+    DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst, mode));
+    DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::RenderAttachment, mode));
 
     DAWN_TRY(ValidateCopyTextureFormatConversion(source->texture->GetFormat().format,
                                                  destination->texture->GetFormat().format));
@@ -546,14 +546,22 @@
                     device->CreateTextureView(source->texture, &srcTextureViewDesc));
 
     // Create bind group after all binding entries are set.
+    UsageValidationMode mode =
+        options->internalUsage ? UsageValidationMode::Internal : UsageValidationMode::Default;
     Ref<BindGroupBase> bindGroup;
-    DAWN_TRY_ASSIGN(bindGroup,
-                    utils::MakeBindGroup(device, layout,
-                                         {{0, uniformBuffer}, {1, sampler}, {2, srcTextureView}}));
+    DAWN_TRY_ASSIGN(bindGroup, utils::MakeBindGroup(
+                                   device, layout,
+                                   {{0, uniformBuffer}, {1, sampler}, {2, srcTextureView}}, mode));
 
     // Create command encoder.
+    CommandEncoderDescriptor commandEncoderDesc;
+    DawnEncoderInternalUsageDescriptor internalUsageDesc;
+    if (options->internalUsage) {
+        internalUsageDesc.useInternalUsages = true;
+        commandEncoderDesc.nextInChain = &internalUsageDesc;
+    }
     Ref<CommandEncoder> encoder;
-    DAWN_TRY_ASSIGN(encoder, device->CreateCommandEncoder());
+    DAWN_TRY_ASSIGN(encoder, device->CreateCommandEncoder(&commandEncoderDesc));
 
     // Prepare dst texture view as color Attachment.
     TextureViewDescriptor dstTextureViewDesc;
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index 82fb66c..e15bee0 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -1407,12 +1407,12 @@
 
 // Implementation details of object creation
 
-ResultOrError<Ref<BindGroupBase>> DeviceBase::CreateBindGroup(
-    const BindGroupDescriptor* descriptor) {
+ResultOrError<Ref<BindGroupBase>> DeviceBase::CreateBindGroup(const BindGroupDescriptor* descriptor,
+                                                              UsageValidationMode mode) {
     DAWN_TRY(ValidateIsAlive());
     if (IsValidationEnabled()) {
-        DAWN_TRY_CONTEXT(ValidateBindGroupDescriptor(this, descriptor), "validating %s against %s",
-                         descriptor, descriptor->layout);
+        DAWN_TRY_CONTEXT(ValidateBindGroupDescriptor(this, descriptor, mode),
+                         "validating %s against %s", descriptor, descriptor->layout);
     }
     return CreateBindGroupImpl(descriptor);
 }
diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h
index e9fab16..10f9087 100644
--- a/src/dawn/native/Device.h
+++ b/src/dawn/native/Device.h
@@ -35,6 +35,7 @@
 #include "dawn/native/RefCountedWithExternalCount.h"
 #include "dawn/native/StagingBuffer.h"
 #include "dawn/native/Toggles.h"
+#include "dawn/native/UsageValidationMode.h"
 
 #include "dawn/native/DawnNative.h"
 #include "dawn/native/dawn_platform.h"
@@ -203,7 +204,9 @@
     Ref<PipelineCacheBase> GetOrCreatePipelineCache(const CacheKey& key);
 
     // Object creation methods that be used in a reentrant manner.
-    ResultOrError<Ref<BindGroupBase>> CreateBindGroup(const BindGroupDescriptor* descriptor);
+    ResultOrError<Ref<BindGroupBase>> CreateBindGroup(
+        const BindGroupDescriptor* descriptor,
+        UsageValidationMode mode = UsageValidationMode::Default);
     ResultOrError<Ref<BindGroupLayoutBase>> CreateBindGroupLayout(
         const BindGroupLayoutDescriptor* descriptor,
         bool allowInternalBinding = false);
diff --git a/src/dawn/native/QueryHelper.cpp b/src/dawn/native/QueryHelper.cpp
index 7832cb3..d8f6481 100644
--- a/src/dawn/native/QueryHelper.cpp
+++ b/src/dawn/native/QueryHelper.cpp
@@ -199,7 +199,8 @@
     Ref<BindGroupBase> bindGroup;
     DAWN_TRY_ASSIGN(
         bindGroup,
-        utils::MakeBindGroup(device, layout, {{0, timestamps}, {1, availability}, {2, params}}));
+        utils::MakeBindGroup(device, layout, {{0, timestamps}, {1, availability}, {2, params}},
+                             UsageValidationMode::Internal));
 
     // Create compute encoder and issue dispatch.
     Ref<ComputePassEncoder> pass = encoder->BeginComputePass();
diff --git a/src/dawn/native/Texture.cpp b/src/dawn/native/Texture.cpp
index 7b1526a..3580ca7 100644
--- a/src/dawn/native/Texture.cpp
+++ b/src/dawn/native/Texture.cpp
@@ -340,7 +340,7 @@
 
     DAWN_INVALID_IF(
         internalUsageDesc != nullptr && !device->IsFeatureEnabled(Feature::DawnInternalUsages),
-        "The dawn-internal-usages feature is not enabled");
+        "The internalUsageDesc is not empty while the dawn-internal-usages feature is not enabled");
 
     const Format* format;
     DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->format));
diff --git a/src/dawn/native/UsageValidationMode.h b/src/dawn/native/UsageValidationMode.h
new file mode 100644
index 0000000..2228bb4
--- /dev/null
+++ b/src/dawn/native/UsageValidationMode.h
@@ -0,0 +1,27 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_USAGEVALIDATIONMODE_H_
+#define SRC_DAWN_NATIVE_USAGEVALIDATIONMODE_H_
+
+namespace dawn::native {
+
+enum class UsageValidationMode {
+    Default,
+    Internal,
+};
+
+}  // namespace dawn::native
+
+#endif  // SRC_DAWN_NATIVE_USAGEVALIDATIONMODE_H_
diff --git a/src/dawn/native/utils/WGPUHelpers.cpp b/src/dawn/native/utils/WGPUHelpers.cpp
index 722476e..2a7a5e0 100644
--- a/src/dawn/native/utils/WGPUHelpers.cpp
+++ b/src/dawn/native/utils/WGPUHelpers.cpp
@@ -165,7 +165,8 @@
 ResultOrError<Ref<BindGroupBase>> MakeBindGroup(
     DeviceBase* device,
     const Ref<BindGroupLayoutBase>& layout,
-    std::initializer_list<BindingInitializationHelper> entriesInitializer) {
+    std::initializer_list<BindingInitializationHelper> entriesInitializer,
+    UsageValidationMode mode) {
     std::vector<BindGroupEntry> entries;
     for (const BindingInitializationHelper& helper : entriesInitializer) {
         entries.push_back(helper.GetAsBinding());
@@ -176,7 +177,7 @@
     descriptor.entryCount = entries.size();
     descriptor.entries = entries.data();
 
-    return device->CreateBindGroup(&descriptor);
+    return device->CreateBindGroup(&descriptor, mode);
 }
 
 const char* GetLabelForTrace(const char* label) {
diff --git a/src/dawn/native/utils/WGPUHelpers.h b/src/dawn/native/utils/WGPUHelpers.h
index 9eab990..45cfa46 100644
--- a/src/dawn/native/utils/WGPUHelpers.h
+++ b/src/dawn/native/utils/WGPUHelpers.h
@@ -21,6 +21,7 @@
 
 #include "dawn/common/RefCounted.h"
 #include "dawn/native/Error.h"
+#include "dawn/native/UsageValidationMode.h"
 #include "dawn/native/dawn_platform.h"
 
 namespace dawn::native::utils {
@@ -110,10 +111,12 @@
     uint64_t size = 0;
 };
 
+// This helper is only used inside dawn native.
 ResultOrError<Ref<BindGroupBase>> MakeBindGroup(
     DeviceBase* device,
     const Ref<BindGroupLayoutBase>& layout,
-    std::initializer_list<BindingInitializationHelper> entriesInitializer);
+    std::initializer_list<BindingInitializationHelper> entriesInitializer,
+    UsageValidationMode mode);
 
 const char* GetLabelForTrace(const char* label);
 
diff --git a/src/dawn/tests/unittests/validation/CopyTextureForBrowserTests.cpp b/src/dawn/tests/unittests/validation/CopyTextureForBrowserTests.cpp
index 5a4e1ec..06c1b3d 100644
--- a/src/dawn/tests/unittests/validation/CopyTextureForBrowserTests.cpp
+++ b/src/dawn/tests/unittests/validation/CopyTextureForBrowserTests.cpp
@@ -22,14 +22,17 @@
 
 class CopyTextureForBrowserTest : public ValidationTest {
   protected:
-    wgpu::Texture Create2DTexture(uint32_t width,
-                                  uint32_t height,
-                                  uint32_t mipLevelCount,
-                                  uint32_t arrayLayerCount,
-                                  wgpu::TextureFormat format,
-                                  wgpu::TextureUsage usage,
-                                  uint32_t sampleCount = 1) {
+    wgpu::Texture Create2DTexture(
+        uint32_t width,
+        uint32_t height,
+        uint32_t mipLevelCount,
+        uint32_t arrayLayerCount,
+        wgpu::TextureFormat format,
+        wgpu::TextureUsage usage,
+        uint32_t sampleCount = 1,
+        const wgpu::DawnTextureInternalUsageDescriptor* internalDesc = nullptr) {
         wgpu::TextureDescriptor descriptor;
+        descriptor.nextInChain = internalDesc;
         descriptor.dimension = wgpu::TextureDimension::e2D;
         descriptor.size.width = width;
         descriptor.size.height = height;
@@ -67,6 +70,17 @@
     }
 };
 
+class CopyTextureForBrowserInternalUsageTest : public CopyTextureForBrowserTest {
+  protected:
+    WGPUDevice CreateTestDevice(dawn::native::Adapter dawnAdapter) override {
+        wgpu::DeviceDescriptor descriptor;
+        wgpu::FeatureName feature = wgpu::FeatureName::DawnInternalUsages;
+        descriptor.requiredFeatures = &feature;
+        descriptor.requiredFeaturesCount = 1;
+        return dawnAdapter.CreateDevice(&descriptor);
+    }
+};
+
 // Tests should be Success
 TEST_F(CopyTextureForBrowserTest, Success) {
     wgpu::Texture source =
@@ -434,3 +448,54 @@
                                   {0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All, options);
     }
 }
+
+// Test that the internal usage can only be set to true when the device internal usage feature is
+// enabled
+TEST_F(CopyTextureForBrowserTest, InternalUsage) {
+    wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
+    internalDesc.internalUsage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding;
+
+    // Validation should fail because internal descriptor is not empty.
+    ASSERT_DEVICE_ERROR(Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
+                                        wgpu::TextureUsage::CopySrc, 1, &internalDesc));
+
+    wgpu::Texture source =
+        Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
+                        wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
+
+    wgpu::Texture destination =
+        Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
+                        wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
+
+    // Validation should fail because of device internal usage feature is missing when internal
+    // usage option is on
+    wgpu::CopyTextureForBrowserOptions options = {};
+    options.internalUsage = true;
+    TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
+                              {0, 0, 0}, {16, 16, 1}, wgpu::TextureAspect::All, options);
+}
+
+// Test that the internal usages are taken into account when interalUsage = true
+TEST_F(CopyTextureForBrowserInternalUsageTest, InternalUsage) {
+    wgpu::DawnTextureInternalUsageDescriptor internalDesc1 = {};
+    internalDesc1.internalUsage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding;
+
+    wgpu::Texture source = Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
+                                           wgpu::TextureUsage::CopySrc, 1, &internalDesc1);
+
+    wgpu::DawnTextureInternalUsageDescriptor internalDesc2 = {};
+    internalDesc2.internalUsage =
+        wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment;
+    wgpu::Texture destination = Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
+                                                wgpu::TextureUsage::CopyDst, 1, &internalDesc2);
+
+    // Without internal usage option should fail usage validation
+    TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
+                              {0, 0, 0}, {16, 16, 1});
+
+    // With internal usage option should pass usage validation
+    wgpu::CopyTextureForBrowserOptions options = {};
+    options.internalUsage = true;
+    TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
+                              {0, 0, 0}, {16, 16, 1}, wgpu::TextureAspect::All, options);
+}