Add chained DawnTextureInternalUsageDescriptor

This chained struct can be used for internally adding usages to
Dawn textures. It will affect how the texture is allocated, but
not affect frontend validation.

One use case for this is so that Chromium can use an internal
copyTextureToTexture command to implement copies from a WebGPU
texture-backed canvas to other Web platform primitives when the
swapchain texture was not explicitly created with CopySrc usage
in Javascript.

Usage:

wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
internalDesc.internalUsage = wgpu::TextureUsage::CopySrc;

wgpu::TextureDescriptor desc = {};
// set properties of desc.
desc.nextInChain = &internalDesc;

device.createTexture(&desc);

Fixed: dawn:1027
Change-Id: Id4d08b5588d4960d150d559aa11502c69f40a674
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/58140
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Austin Eng 2021-07-27 19:59:58 +00:00 committed by Dawn LUCI CQ
parent 7e50a7fad3
commit 0eff5987f0
15 changed files with 291 additions and 54 deletions

View File

@ -880,7 +880,8 @@
{"name": "timestamp query", "type": "bool", "default": "false"},
{"name": "multi planar formats", "type": "bool", "default": "false"},
{"name": "depth clamping", "type": "bool", "default": "false"},
{"name": "invalid extension", "type": "bool", "default": "false"}
{"name": "invalid extension", "type": "bool", "default": "false"},
{"name": "dawn internal usages", "type": "bool", "default": "false"}
]
},
"double": {
@ -1852,7 +1853,8 @@
{"value": 8, "name": "surface descriptor from windows core window"},
{"value": 9, "name": "external texture binding entry"},
{"value": 10, "name": "external texture binding layout"},
{"value": 11, "name": "surface descriptor from windows swap chain panel"}
{"value": 11, "name": "surface descriptor from windows swap chain panel"},
{"value": 1000, "name": "dawn texture internal usage descriptor"}
]
},
"texture": {
@ -2105,5 +2107,12 @@
},
"uint8_t": {
"category": "native"
},
"dawn texture internal usage descriptor": {
"category": "structure",
"chained": true,
"members": [
{"name": "internal usage", "type": "texture usage", "default": "none"}
]
}
}

View File

@ -0,0 +1,18 @@
# Dawn Internal Usages
The `dawn-internal-usages` extension allows adding additional usage which affects how a texture is allocated, but does not affect frontend validation.
One use case for this is so that Chromium can use an internal copyTextureToTexture command to implement copies from a WebGPU texture-backed canvas to other Web platform primitives when the swapchain texture was not explicitly created with CopySrc usage in Javascript.
```
Usage:
wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
internalDesc.internalUsage = wgpu::TextureUsage::CopySrc;
wgpu::TextureDescriptor desc = {};
// set properties of desc.
desc.nextInChain = &internalDesc;
device.createTexture(&desc);
```

View File

@ -20,6 +20,7 @@ namespace dawn_native {
AdapterBase::AdapterBase(InstanceBase* instance, wgpu::BackendType backend)
: mInstance(instance), mBackend(backend) {
mSupportedExtensions.EnableExtension(Extension::DawnInternalUsages);
}
wgpu::BackendType AdapterBase::GetBackendType() const {

View File

@ -56,7 +56,14 @@ namespace dawn_native {
{Extension::DepthClamping,
{"depth_clamping", "Clamp depth to [0, 1] in NDC space instead of clipping",
"https://bugs.chromium.org/p/dawn/issues/detail?id=716"},
&WGPUDeviceProperties::depthClamping}}};
&WGPUDeviceProperties::depthClamping},
{Extension::DawnInternalUsages,
{"dawn-internal-usages",
"Add internal usages to resources to affect how the texture is allocated, but not "
"frontend validation. Other internal commands may access this usage.",
"https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/extensions/"
"dawn_internal_usages.md"},
&WGPUDeviceProperties::dawnInternalUsages}}};
} // anonymous namespace

View File

@ -31,6 +31,9 @@ namespace dawn_native {
MultiPlanarFormats,
DepthClamping,
// Dawn-specific
DawnInternalUsages,
EnumCount,
InvalidEnum = EnumCount,
ExtensionMin = TextureCompressionBC,

View File

@ -20,6 +20,7 @@
#include "common/Constants.h"
#include "common/Math.h"
#include "dawn_native/Adapter.h"
#include "dawn_native/ChainUtils_autogen.h"
#include "dawn_native/Device.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/PassResourceUsage.h"
@ -104,7 +105,9 @@ namespace dawn_native {
}
}
MaybeError ValidateSampleCount(const TextureDescriptor* descriptor, const Format* format) {
MaybeError ValidateSampleCount(const TextureDescriptor* descriptor,
wgpu::TextureUsage usage,
const Format* format) {
if (!IsValidSampleCount(descriptor->sampleCount)) {
return DAWN_VALIDATION_ERROR("The sample count of the texture is not supported.");
}
@ -132,7 +135,7 @@ namespace dawn_native {
// Compressed formats are not renderable. They cannot support multisample.
ASSERT(!format->isCompressed);
if (descriptor->usage & wgpu::TextureUsage::Storage) {
if (usage & wgpu::TextureUsage::Storage) {
return DAWN_VALIDATION_ERROR(
"The sample counts of the storage textures must be 1.");
}
@ -217,30 +220,30 @@ namespace dawn_native {
return {};
}
MaybeError ValidateTextureUsage(const TextureDescriptor* descriptor, const Format* format) {
DAWN_TRY(dawn_native::ValidateTextureUsage(descriptor->usage));
MaybeError ValidateTextureUsage(const TextureDescriptor* descriptor,
wgpu::TextureUsage usage,
const Format* format) {
DAWN_TRY(dawn_native::ValidateTextureUsage(usage));
constexpr wgpu::TextureUsage kValidCompressedUsages = wgpu::TextureUsage::Sampled |
wgpu::TextureUsage::CopySrc |
wgpu::TextureUsage::CopyDst;
if (format->isCompressed && !IsSubset(descriptor->usage, kValidCompressedUsages)) {
if (format->isCompressed && !IsSubset(usage, kValidCompressedUsages)) {
return DAWN_VALIDATION_ERROR(
"Compressed texture format is incompatible with the texture usage");
}
if (!format->isRenderable &&
(descriptor->usage & wgpu::TextureUsage::RenderAttachment)) {
if (!format->isRenderable && (usage & wgpu::TextureUsage::RenderAttachment)) {
return DAWN_VALIDATION_ERROR(
"Non-renderable format used with RenderAttachment usage");
}
if (!format->supportsStorageUsage &&
(descriptor->usage & wgpu::TextureUsage::Storage)) {
if (!format->supportsStorageUsage && (usage & wgpu::TextureUsage::Storage)) {
return DAWN_VALIDATION_ERROR("Format cannot be used in storage textures");
}
constexpr wgpu::TextureUsage kValidMultiPlanarUsages = wgpu::TextureUsage::Sampled;
if (format->IsMultiPlanar() && !IsSubset(descriptor->usage, kValidMultiPlanarUsages)) {
if (format->IsMultiPlanar() && !IsSubset(usage, kValidMultiPlanarUsages)) {
return DAWN_VALIDATION_ERROR("Multi-planar format doesn't have valid usage.");
}
@ -251,19 +254,32 @@ namespace dawn_native {
MaybeError ValidateTextureDescriptor(const DeviceBase* device,
const TextureDescriptor* descriptor) {
if (descriptor->nextInChain != nullptr) {
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
}
DAWN_TRY(ValidateSingleSType(descriptor->nextInChain,
wgpu::SType::DawnTextureInternalUsageDescriptor));
const DawnTextureInternalUsageDescriptor* internalUsageDesc = nullptr;
FindInChain(descriptor->nextInChain, &internalUsageDesc);
if (descriptor->dimension == wgpu::TextureDimension::e1D) {
return DAWN_VALIDATION_ERROR("1D textures aren't supported (yet).");
}
if (internalUsageDesc != nullptr &&
!device->IsExtensionEnabled(Extension::DawnInternalUsages)) {
return DAWN_VALIDATION_ERROR("The dawn-internal-usages feature is not enabled");
}
const Format* format;
DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->format));
DAWN_TRY(ValidateTextureUsage(descriptor, format));
wgpu::TextureUsage usage = descriptor->usage;
if (internalUsageDesc != nullptr) {
usage |= internalUsageDesc->internalUsage;
}
DAWN_TRY(ValidateTextureUsage(descriptor, usage, format));
DAWN_TRY(ValidateTextureDimension(descriptor->dimension));
DAWN_TRY(ValidateSampleCount(descriptor, format));
DAWN_TRY(ValidateSampleCount(descriptor, usage, format));
if (descriptor->size.width == 0 || descriptor->size.height == 0 ||
descriptor->size.depthOrArrayLayers == 0 || descriptor->mipLevelCount == 0) {
@ -426,15 +442,22 @@ namespace dawn_native {
mMipLevelCount(descriptor->mipLevelCount),
mSampleCount(descriptor->sampleCount),
mUsage(descriptor->usage),
mInternalUsage(mUsage),
mState(state) {
uint32_t subresourceCount =
mMipLevelCount * GetArrayLayers() * GetAspectCount(mFormat.aspects);
mIsSubresourceContentInitializedAtIndex = std::vector<bool>(subresourceCount, false);
const DawnTextureInternalUsageDescriptor* internalUsageDesc = nullptr;
FindInChain(descriptor->nextInChain, &internalUsageDesc);
if (internalUsageDesc != nullptr) {
mInternalUsage |= internalUsageDesc->internalUsage;
}
// Add readonly storage usage if the texture has a storage usage. The validation rules in
// ValidateSyncScopeResourceUsage will make sure we don't use both at the same time.
if (mUsage & wgpu::TextureUsage::Storage) {
mUsage |= kReadOnlyStorageTexture;
if (mInternalUsage & wgpu::TextureUsage::Storage) {
mInternalUsage |= kReadOnlyStorageTexture;
}
}
@ -505,6 +528,10 @@ namespace dawn_native {
ASSERT(!IsError());
return mUsage;
}
wgpu::TextureUsage TextureBase::GetInternalUsage() const {
ASSERT(!IsError());
return mInternalUsage;
}
TextureBase::TextureState TextureBase::GetTextureState() const {
ASSERT(!IsError());

View File

@ -61,7 +61,13 @@ namespace dawn_native {
SubresourceRange GetAllSubresources() const;
uint32_t GetSampleCount() const;
uint32_t GetSubresourceCount() const;
// |GetUsage| returns the usage with which the texture was created using the base WebGPU
// API. The dawn-internal-usages extension may add additional usages. |GetInternalUsage|
// returns the union of base usage and the usages added by the extension.
wgpu::TextureUsage GetUsage() const;
wgpu::TextureUsage GetInternalUsage() const;
TextureState GetTextureState() const;
uint32_t GetSubresourceIndex(uint32_t mipLevel, uint32_t arraySlice, Aspect aspect) const;
bool IsSubresourceContentInitialized(const SubresourceRange& range) const;
@ -100,6 +106,7 @@ namespace dawn_native {
uint32_t mMipLevelCount;
uint32_t mSampleCount;
wgpu::TextureUsage mUsage = wgpu::TextureUsage::None;
wgpu::TextureUsage mInternalUsage = wgpu::TextureUsage::None;
TextureState mState;
// TODO(crbug.com/dawn/845): Use a more optimized data structure to save space

View File

@ -496,8 +496,8 @@ namespace dawn_native { namespace d3d12 {
// This will need to be much more nuanced when WebGPU has
// texture view compatibility rules.
const bool needsTypelessFormat =
GetFormat().HasDepthOrStencil() && (GetUsage() & wgpu::TextureUsage::Sampled) != 0;
const bool needsTypelessFormat = GetFormat().HasDepthOrStencil() &&
(GetInternalUsage() & wgpu::TextureUsage::Sampled) != 0;
DXGI_FORMAT dxgiFormat = needsTypelessFormat
? D3D12TypelessTextureFormat(GetFormat().format)
@ -509,7 +509,7 @@ namespace dawn_native { namespace d3d12 {
resourceDescriptor.SampleDesc.Quality = 0;
resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
resourceDescriptor.Flags =
D3D12ResourceFlags(GetUsage(), GetFormat(), IsMultisampledTexture());
D3D12ResourceFlags(GetInternalUsage(), GetFormat(), IsMultisampledTexture());
mD3D12ResourceFlags = resourceDescriptor.Flags;
DAWN_TRY_ASSIGN(mResourceAllocation,

View File

@ -56,6 +56,8 @@ namespace dawn_native { namespace metal {
using TextureBase::TextureBase;
~Texture() override;
NSRef<MTLTextureDescriptor> CreateMetalTextureDescriptor() const;
MaybeError InitializeAsInternalTexture(const TextureDescriptor* descriptor);
MaybeError InitializeFromIOSurface(const ExternalImageDescriptor* descriptor,
const TextureDescriptor* textureDescriptor,

View File

@ -302,42 +302,38 @@ namespace dawn_native { namespace metal {
return {};
}
NSRef<MTLTextureDescriptor> CreateMetalTextureDescriptor(DeviceBase* device,
const TextureDescriptor* descriptor) {
NSRef<MTLTextureDescriptor> Texture::CreateMetalTextureDescriptor() const {
NSRef<MTLTextureDescriptor> mtlDescRef = AcquireNSRef([MTLTextureDescriptor new]);
MTLTextureDescriptor* mtlDesc = mtlDescRef.Get();
mtlDesc.width = descriptor->size.width;
mtlDesc.height = descriptor->size.height;
mtlDesc.sampleCount = descriptor->sampleCount;
mtlDesc.width = GetWidth();
mtlDesc.height = GetHeight();
mtlDesc.sampleCount = GetSampleCount();
// TODO: add MTLTextureUsagePixelFormatView when needed when we support format
// reinterpretation.
mtlDesc.usage = MetalTextureUsage(device->GetValidInternalFormat(descriptor->format),
descriptor->usage, descriptor->sampleCount);
mtlDesc.pixelFormat = MetalPixelFormat(descriptor->format);
mtlDesc.mipmapLevelCount = descriptor->mipLevelCount;
mtlDesc.usage = MetalTextureUsage(GetFormat(), GetInternalUsage(), GetSampleCount());
mtlDesc.pixelFormat = MetalPixelFormat(GetFormat().format);
mtlDesc.mipmapLevelCount = GetNumMipLevels();
mtlDesc.storageMode = MTLStorageModePrivate;
// Choose the correct MTLTextureType and paper over differences in how the array layer count
// is specified.
mtlDesc.depth = descriptor->size.depthOrArrayLayers;
mtlDesc.arrayLength = 1;
switch (descriptor->dimension) {
switch (GetDimension()) {
case wgpu::TextureDimension::e2D:
if (mtlDesc.depth > 1) {
mtlDesc.depth = 1;
mtlDesc.arrayLength = GetArrayLayers();
if (mtlDesc.arrayLength > 1) {
ASSERT(mtlDesc.sampleCount == 1);
mtlDesc.textureType = MTLTextureType2DArray;
mtlDesc.arrayLength = mtlDesc.depth;
mtlDesc.depth = 1;
} else if (mtlDesc.sampleCount > 1) {
mtlDesc.textureType = MTLTextureType2DMultisample;
} else {
if (mtlDesc.sampleCount > 1) {
mtlDesc.textureType = MTLTextureType2DMultisample;
} else {
mtlDesc.textureType = MTLTextureType2D;
}
mtlDesc.textureType = MTLTextureType2D;
}
break;
case wgpu::TextureDimension::e3D:
mtlDesc.depth = GetDepth();
mtlDesc.arrayLength = 1;
ASSERT(mtlDesc.sampleCount == 1);
mtlDesc.textureType = MTLTextureType3D;
break;
@ -386,7 +382,7 @@ namespace dawn_native { namespace metal {
MaybeError Texture::InitializeAsInternalTexture(const TextureDescriptor* descriptor) {
Device* device = ToBackend(GetDevice());
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor(device, descriptor);
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor();
mMtlUsage = [*mtlDesc usage];
mMtlTexture =
AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc.Get()]);
@ -405,7 +401,7 @@ namespace dawn_native { namespace metal {
void Texture::InitializeAsWrapping(const TextureDescriptor* descriptor,
NSPRef<id<MTLTexture>> wrapped) {
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor(GetDevice(), descriptor);
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor();
mMtlUsage = [*mtlDesc usage];
mMtlTexture = std::move(wrapped);
}
@ -416,8 +412,7 @@ namespace dawn_native { namespace metal {
uint32_t plane) {
Device* device = ToBackend(GetDevice());
NSRef<MTLTextureDescriptor> mtlDesc =
CreateMetalTextureDescriptor(device, textureDescriptor);
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor();
[*mtlDesc setStorageMode:kIOSurfaceStorageMode];
mMtlUsage = [*mtlDesc usage];
@ -667,7 +662,7 @@ namespace dawn_native { namespace metal {
Texture* texture = ToBackend(GetTexture());
id<MTLTexture> mtlTexture = texture->GetMTLTexture();
if (!UsageNeedsTextureView(texture->GetUsage())) {
if (!UsageNeedsTextureView(texture->GetInternalUsage())) {
mMtlTextureView = nullptr;
} else if (!RequiresCreatingNewTextureView(texture, descriptor)) {
mMtlTextureView = mtlTexture;

View File

@ -31,7 +31,7 @@ namespace dawn_native { namespace null {
mAdapterType = wgpu::AdapterType::CPU;
// Enable all extensions by default for the convenience of tests.
mSupportedExtensions.extensionsBitSet.flip();
mSupportedExtensions.extensionsBitSet.set();
}
Adapter::~Adapter() = default;

View File

@ -16,6 +16,7 @@
#include "common/Platform.h"
#include "dawn_native/BackendConnection.h"
#include "dawn_native/ChainUtils_autogen.h"
#include "dawn_native/Error.h"
#include "dawn_native/ErrorData.h"
#include "dawn_native/VulkanBackend.h"
@ -698,6 +699,14 @@ namespace dawn_native { namespace vulkan {
const TextureDescriptor* textureDescriptor =
reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor);
const DawnTextureInternalUsageDescriptor* internalUsageDesc = nullptr;
FindInChain(textureDescriptor->nextInChain, &internalUsageDesc);
wgpu::TextureUsage usage = textureDescriptor->usage;
if (internalUsageDesc != nullptr) {
usage |= internalUsageDesc->internalUsage;
}
// Check services support this combination of handle type / image info
if (!mExternalSemaphoreService->Supported()) {
return DAWN_VALIDATION_ERROR("External semaphore usage not supported");
@ -705,8 +714,7 @@ namespace dawn_native { namespace vulkan {
if (!mExternalMemoryService->SupportsImportMemory(
VulkanImageFormat(this, textureDescriptor->format), VK_IMAGE_TYPE_2D,
VK_IMAGE_TILING_OPTIMAL,
VulkanImageUsage(textureDescriptor->usage,
GetValidInternalFormat(textureDescriptor->format)),
VulkanImageUsage(usage, GetValidInternalFormat(textureDescriptor->format)),
VK_IMAGE_CREATE_ALIAS_BIT_KHR)) {
return DAWN_VALIDATION_ERROR("External memory usage not supported");
}

View File

@ -398,7 +398,7 @@ namespace dawn_native { namespace vulkan {
// happen so we must prepare for the pessimistic case and always use the GENERAL
// layout.
case wgpu::TextureUsage::Sampled:
if (texture->GetUsage() & wgpu::TextureUsage::Storage) {
if (texture->GetInternalUsage() & wgpu::TextureUsage::Storage) {
return VK_IMAGE_LAYOUT_GENERAL;
} else {
return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@ -538,7 +538,7 @@ namespace dawn_native { namespace vulkan {
createInfo.flags = 0;
createInfo.format = VulkanImageFormat(device, GetFormat().format);
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
createInfo.usage = VulkanImageUsage(GetUsage(), GetFormat()) | extraUsages;
createInfo.usage = VulkanImageUsage(GetInternalUsage(), GetFormat()) | extraUsages;
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr;
@ -584,7 +584,7 @@ namespace dawn_native { namespace vulkan {
MaybeError Texture::InitializeFromExternal(const ExternalImageDescriptorVk* descriptor,
external_memory::Service* externalMemoryService) {
VkFormat format = VulkanImageFormat(ToBackend(GetDevice()), GetFormat().format);
VkImageUsageFlags usage = VulkanImageUsage(GetUsage(), GetFormat());
VkImageUsageFlags usage = VulkanImageUsage(GetInternalUsage(), GetFormat());
if (!externalMemoryService->SupportsCreateImage(descriptor, format, usage)) {
return DAWN_VALIDATION_ERROR("Creating an image from external memory is not supported");
}

View File

@ -202,6 +202,7 @@ test("dawn_unittests") {
"unittests/validation/ExternalTextureTests.cpp",
"unittests/validation/GetBindGroupLayoutValidationTests.cpp",
"unittests/validation/IndexBufferValidationTests.cpp",
"unittests/validation/InternalUsageValidationTests.cpp",
"unittests/validation/MinimumBufferSizeValidationTests.cpp",
"unittests/validation/MultipleDeviceTests.cpp",
"unittests/validation/QueryValidationTests.cpp",

View File

@ -0,0 +1,159 @@
// Copyright 2021 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.
#include "tests/unittests/validation/ValidationTest.h"
#include "utils/WGPUHelpers.h"
class TextureInternalUsageValidationDisabledTest : public ValidationTest {};
// Test that using the extension is an error if it is not enabled
TEST_F(TextureInternalUsageValidationDisabledTest, RequiresExtension) {
wgpu::TextureDescriptor textureDesc = {};
textureDesc.size = {1, 1};
textureDesc.usage = wgpu::TextureUsage::CopySrc;
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
// Control case: Normal texture creation works
device.CreateTexture(&textureDesc);
wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
textureDesc.nextInChain = &internalDesc;
// Error with chained extension struct.
ASSERT_DEVICE_ERROR(device.CreateTexture(&textureDesc));
// Also does not work with various internal usages.
internalDesc.internalUsage = wgpu::TextureUsage::CopySrc;
ASSERT_DEVICE_ERROR(device.CreateTexture(&textureDesc));
internalDesc.internalUsage = wgpu::TextureUsage::CopyDst;
ASSERT_DEVICE_ERROR(device.CreateTexture(&textureDesc));
}
class TextureInternalUsageValidationTest : public ValidationTest {
WGPUDevice CreateTestDevice() override {
dawn_native::DeviceDescriptor descriptor;
descriptor.requiredExtensions.push_back("dawn-internal-usages");
return adapter.CreateDevice(&descriptor);
}
};
// Test that internal usages can be passed in a chained descriptor.
TEST_F(TextureInternalUsageValidationTest, Basic) {
wgpu::TextureDescriptor textureDesc = {};
textureDesc.size = {1, 1};
textureDesc.usage = wgpu::TextureUsage::CopySrc;
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
textureDesc.nextInChain = &internalDesc;
// Internal usage: none
device.CreateTexture(&textureDesc);
// Internal usage is the same as the base usage.
internalDesc.internalUsage = wgpu::TextureUsage::CopySrc;
device.CreateTexture(&textureDesc);
// Internal usage adds to the base usage.
internalDesc.internalUsage = wgpu::TextureUsage::CopyDst;
device.CreateTexture(&textureDesc);
}
// Test that internal usages takes part in other validation that
// depends on the usage.
TEST_F(TextureInternalUsageValidationTest, UsageValidation) {
{
wgpu::TextureDescriptor textureDesc = {};
textureDesc.size = {1, 1};
textureDesc.usage = wgpu::TextureUsage::CopySrc;
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
textureDesc.nextInChain = &internalDesc;
// Internal usage adds an invalid usage.
internalDesc.internalUsage = static_cast<wgpu::TextureUsage>(-1);
ASSERT_DEVICE_ERROR(device.CreateTexture(&textureDesc));
}
{
wgpu::TextureDescriptor textureDesc = {};
textureDesc.size = {1, 1};
textureDesc.usage = wgpu::TextureUsage::CopySrc;
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
textureDesc.sampleCount = 4;
// Control case: multisampled texture
device.CreateTexture(&textureDesc);
wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
textureDesc.nextInChain = &internalDesc;
// OK: internal usage adds nothing.
device.CreateTexture(&textureDesc);
// Internal usage adds storage usage which is invalid
// with multisampling.
internalDesc.internalUsage = wgpu::TextureUsage::Storage;
ASSERT_DEVICE_ERROR(device.CreateTexture(&textureDesc));
}
}
// Test that internal usage does not add to the validated usage
// for command encoding
TEST_F(TextureInternalUsageValidationTest, CommandValidation) {
wgpu::TextureDescriptor textureDesc = {};
textureDesc.size = {1, 1};
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
textureDesc.usage = wgpu::TextureUsage::CopyDst;
wgpu::Texture dst = device.CreateTexture(&textureDesc);
textureDesc.usage = wgpu::TextureUsage::CopySrc;
wgpu::Texture src = device.CreateTexture(&textureDesc);
textureDesc.usage = wgpu::TextureUsage::None;
wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
textureDesc.nextInChain = &internalDesc;
internalDesc.internalUsage = wgpu::TextureUsage::CopySrc;
wgpu::Texture srcInternal = device.CreateTexture(&textureDesc);
// Control: src -> dst
{
wgpu::ImageCopyTexture srcImageCopyTexture = utils::CreateImageCopyTexture(src, 0, {0, 0});
wgpu::ImageCopyTexture dstImageCopyTexture = utils::CreateImageCopyTexture(dst, 0, {0, 0});
wgpu::Extent3D extent3D = {1, 1};
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.CopyTextureToTexture(&srcImageCopyTexture, &dstImageCopyTexture, &extent3D);
encoder.Finish();
}
// Invalid: src internal -> dst
{
wgpu::ImageCopyTexture srcImageCopyTexture =
utils::CreateImageCopyTexture(srcInternal, 0, {0, 0});
wgpu::ImageCopyTexture dstImageCopyTexture = utils::CreateImageCopyTexture(dst, 0, {0, 0});
wgpu::Extent3D extent3D = {1, 1};
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.CopyTextureToTexture(&srcImageCopyTexture, &dstImageCopyTexture, &extent3D);
ASSERT_DEVICE_ERROR(encoder.Finish());
}
}