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": "timestamp query", "type": "bool", "default": "false"},
{"name": "multi planar formats", "type": "bool", "default": "false"}, {"name": "multi planar formats", "type": "bool", "default": "false"},
{"name": "depth clamping", "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": { "double": {
@ -1852,7 +1853,8 @@
{"value": 8, "name": "surface descriptor from windows core window"}, {"value": 8, "name": "surface descriptor from windows core window"},
{"value": 9, "name": "external texture binding entry"}, {"value": 9, "name": "external texture binding entry"},
{"value": 10, "name": "external texture binding layout"}, {"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": { "texture": {
@ -2105,5 +2107,12 @@
}, },
"uint8_t": { "uint8_t": {
"category": "native" "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) AdapterBase::AdapterBase(InstanceBase* instance, wgpu::BackendType backend)
: mInstance(instance), mBackend(backend) { : mInstance(instance), mBackend(backend) {
mSupportedExtensions.EnableExtension(Extension::DawnInternalUsages);
} }
wgpu::BackendType AdapterBase::GetBackendType() const { wgpu::BackendType AdapterBase::GetBackendType() const {

View File

@ -56,7 +56,14 @@ namespace dawn_native {
{Extension::DepthClamping, {Extension::DepthClamping,
{"depth_clamping", "Clamp depth to [0, 1] in NDC space instead of clipping", {"depth_clamping", "Clamp depth to [0, 1] in NDC space instead of clipping",
"https://bugs.chromium.org/p/dawn/issues/detail?id=716"}, "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 } // anonymous namespace

View File

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

View File

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

View File

@ -61,7 +61,13 @@ namespace dawn_native {
SubresourceRange GetAllSubresources() const; SubresourceRange GetAllSubresources() const;
uint32_t GetSampleCount() const; uint32_t GetSampleCount() const;
uint32_t GetSubresourceCount() 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 GetUsage() const;
wgpu::TextureUsage GetInternalUsage() const;
TextureState GetTextureState() const; TextureState GetTextureState() const;
uint32_t GetSubresourceIndex(uint32_t mipLevel, uint32_t arraySlice, Aspect aspect) const; uint32_t GetSubresourceIndex(uint32_t mipLevel, uint32_t arraySlice, Aspect aspect) const;
bool IsSubresourceContentInitialized(const SubresourceRange& range) const; bool IsSubresourceContentInitialized(const SubresourceRange& range) const;
@ -100,6 +106,7 @@ namespace dawn_native {
uint32_t mMipLevelCount; uint32_t mMipLevelCount;
uint32_t mSampleCount; uint32_t mSampleCount;
wgpu::TextureUsage mUsage = wgpu::TextureUsage::None; wgpu::TextureUsage mUsage = wgpu::TextureUsage::None;
wgpu::TextureUsage mInternalUsage = wgpu::TextureUsage::None;
TextureState mState; TextureState mState;
// TODO(crbug.com/dawn/845): Use a more optimized data structure to save space // 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 // This will need to be much more nuanced when WebGPU has
// texture view compatibility rules. // texture view compatibility rules.
const bool needsTypelessFormat = const bool needsTypelessFormat = GetFormat().HasDepthOrStencil() &&
GetFormat().HasDepthOrStencil() && (GetUsage() & wgpu::TextureUsage::Sampled) != 0; (GetInternalUsage() & wgpu::TextureUsage::Sampled) != 0;
DXGI_FORMAT dxgiFormat = needsTypelessFormat DXGI_FORMAT dxgiFormat = needsTypelessFormat
? D3D12TypelessTextureFormat(GetFormat().format) ? D3D12TypelessTextureFormat(GetFormat().format)
@ -509,7 +509,7 @@ namespace dawn_native { namespace d3d12 {
resourceDescriptor.SampleDesc.Quality = 0; resourceDescriptor.SampleDesc.Quality = 0;
resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
resourceDescriptor.Flags = resourceDescriptor.Flags =
D3D12ResourceFlags(GetUsage(), GetFormat(), IsMultisampledTexture()); D3D12ResourceFlags(GetInternalUsage(), GetFormat(), IsMultisampledTexture());
mD3D12ResourceFlags = resourceDescriptor.Flags; mD3D12ResourceFlags = resourceDescriptor.Flags;
DAWN_TRY_ASSIGN(mResourceAllocation, DAWN_TRY_ASSIGN(mResourceAllocation,

View File

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

View File

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

View File

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

View File

@ -16,6 +16,7 @@
#include "common/Platform.h" #include "common/Platform.h"
#include "dawn_native/BackendConnection.h" #include "dawn_native/BackendConnection.h"
#include "dawn_native/ChainUtils_autogen.h"
#include "dawn_native/Error.h" #include "dawn_native/Error.h"
#include "dawn_native/ErrorData.h" #include "dawn_native/ErrorData.h"
#include "dawn_native/VulkanBackend.h" #include "dawn_native/VulkanBackend.h"
@ -698,6 +699,14 @@ namespace dawn_native { namespace vulkan {
const TextureDescriptor* textureDescriptor = const TextureDescriptor* textureDescriptor =
reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor); 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 // Check services support this combination of handle type / image info
if (!mExternalSemaphoreService->Supported()) { if (!mExternalSemaphoreService->Supported()) {
return DAWN_VALIDATION_ERROR("External semaphore usage not supported"); return DAWN_VALIDATION_ERROR("External semaphore usage not supported");
@ -705,8 +714,7 @@ namespace dawn_native { namespace vulkan {
if (!mExternalMemoryService->SupportsImportMemory( if (!mExternalMemoryService->SupportsImportMemory(
VulkanImageFormat(this, textureDescriptor->format), VK_IMAGE_TYPE_2D, VulkanImageFormat(this, textureDescriptor->format), VK_IMAGE_TYPE_2D,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_TILING_OPTIMAL,
VulkanImageUsage(textureDescriptor->usage, VulkanImageUsage(usage, GetValidInternalFormat(textureDescriptor->format)),
GetValidInternalFormat(textureDescriptor->format)),
VK_IMAGE_CREATE_ALIAS_BIT_KHR)) { VK_IMAGE_CREATE_ALIAS_BIT_KHR)) {
return DAWN_VALIDATION_ERROR("External memory usage not supported"); 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 // happen so we must prepare for the pessimistic case and always use the GENERAL
// layout. // layout.
case wgpu::TextureUsage::Sampled: case wgpu::TextureUsage::Sampled:
if (texture->GetUsage() & wgpu::TextureUsage::Storage) { if (texture->GetInternalUsage() & wgpu::TextureUsage::Storage) {
return VK_IMAGE_LAYOUT_GENERAL; return VK_IMAGE_LAYOUT_GENERAL;
} else { } else {
return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@ -538,7 +538,7 @@ namespace dawn_native { namespace vulkan {
createInfo.flags = 0; createInfo.flags = 0;
createInfo.format = VulkanImageFormat(device, GetFormat().format); createInfo.format = VulkanImageFormat(device, GetFormat().format);
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 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.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0; createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr; createInfo.pQueueFamilyIndices = nullptr;
@ -584,7 +584,7 @@ namespace dawn_native { namespace vulkan {
MaybeError Texture::InitializeFromExternal(const ExternalImageDescriptorVk* descriptor, MaybeError Texture::InitializeFromExternal(const ExternalImageDescriptorVk* descriptor,
external_memory::Service* externalMemoryService) { external_memory::Service* externalMemoryService) {
VkFormat format = VulkanImageFormat(ToBackend(GetDevice()), GetFormat().format); VkFormat format = VulkanImageFormat(ToBackend(GetDevice()), GetFormat().format);
VkImageUsageFlags usage = VulkanImageUsage(GetUsage(), GetFormat()); VkImageUsageFlags usage = VulkanImageUsage(GetInternalUsage(), GetFormat());
if (!externalMemoryService->SupportsCreateImage(descriptor, format, usage)) { if (!externalMemoryService->SupportsCreateImage(descriptor, format, usage)) {
return DAWN_VALIDATION_ERROR("Creating an image from external memory is not supported"); 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/ExternalTextureTests.cpp",
"unittests/validation/GetBindGroupLayoutValidationTests.cpp", "unittests/validation/GetBindGroupLayoutValidationTests.cpp",
"unittests/validation/IndexBufferValidationTests.cpp", "unittests/validation/IndexBufferValidationTests.cpp",
"unittests/validation/InternalUsageValidationTests.cpp",
"unittests/validation/MinimumBufferSizeValidationTests.cpp", "unittests/validation/MinimumBufferSizeValidationTests.cpp",
"unittests/validation/MultipleDeviceTests.cpp", "unittests/validation/MultipleDeviceTests.cpp",
"unittests/validation/QueryValidationTests.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());
}
}