Add WGPUDawnEncoderInternalUsageDescriptor

This descriptor, when chained on WGPUCommandEncoderDescriptor makes
internal usages visible to validation.

This CL is to help implement WebGPU Swiftshader support in Chrome.

Bug: chromium:1266550
Change-Id: I7253fe45003e9ad5ac4d8ddd2d4782989e9b5c27
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/76440
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
Austin Eng 2022-01-18 21:54:25 +00:00 committed by Dawn LUCI CQ
parent ddca7bc855
commit aa9475e973
10 changed files with 290 additions and 60 deletions

View File

@ -2369,7 +2369,8 @@
{"value": 11, "name": "surface descriptor from windows swap chain panel", "tags": ["dawn"]}, {"value": 11, "name": "surface descriptor from windows swap chain panel", "tags": ["dawn"]},
{"value": 1000, "name": "dawn texture internal usage descriptor", "tags": ["dawn"]}, {"value": 1000, "name": "dawn texture internal usage descriptor", "tags": ["dawn"]},
{"value": 1001, "name": "primitive depth clamping state", "tags": ["dawn", "emscripten"]}, {"value": 1001, "name": "primitive depth clamping state", "tags": ["dawn", "emscripten"]},
{"value": 1002, "name": "dawn toggles device descriptor", "tags": ["dawn", "native"]} {"value": 1002, "name": "dawn toggles device descriptor", "tags": ["dawn", "native"]},
{"value": 1003, "name": "dawn encoder internal usage descriptor", "tags": ["dawn"]}
] ]
}, },
"texture": { "texture": {
@ -2733,5 +2734,13 @@
"members": [ "members": [
{"name": "internal usage", "type": "texture usage", "default": "none"} {"name": "internal usage", "type": "texture usage", "default": "none"}
] ]
},
"dawn encoder internal usage descriptor": {
"category": "structure",
"chained": "in",
"tags": ["dawn"],
"members": [
{"name": "use internal usages", "type": "bool", "default": "false"}
]
} }
} }

View File

@ -1,12 +1,11 @@
# Dawn Internal Usages # Dawn Internal Usages
The `dawn-internal-usages` feature allows adding additional usage which affects how a texture is allocated, but does not affect frontend validation. The `dawn-internal-usages` feature allows adding additional usage which affects how a texture is allocated, but does not affect normal 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. Adds `WGPUDawnTextureInternalUsageDescriptor` for specifying additional internal usages to create a texture with.
Example Usage:
``` ```
Usage:
wgpu::DawnTextureInternalUsageDescriptor internalDesc = {}; wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
internalDesc.internalUsage = wgpu::TextureUsage::CopySrc; internalDesc.internalUsage = wgpu::TextureUsage::CopySrc;
@ -14,5 +13,26 @@ wgpu::TextureDescriptor desc = {};
// set properties of desc. // set properties of desc.
desc.nextInChain = &internalDesc; desc.nextInChain = &internalDesc;
device.createTexture(&desc); device.CreateTexture(&desc);
``` ```
Adds `WGPUDawnEncoderInternalUsageDescriptor` which may be chained on `WGPUCommandEncoderDescriptor`. Setting `WGPUDawnEncoderInternalUsageDescriptor::useInternalUsages` to `true` means that internal resource usages will be visible during validation. ex.) A texture that has `WGPUTextureUsage_CopySrc` in `WGPUDawnEncoderInternalUsageDescriptor::internalUsage`, but not in `WGPUTextureDescriptor::usage` may be used as the source of a copy command.
Example Usage:
```
wgpu::DawnEncoderInternalUsageDescriptor internalEncoderDesc = { true };
wgpu::CommandEncoderDescriptor encoderDesc = {};
encoderDesc.nextInChain = &internalEncoderDesc;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(&encoderDesc);
// This will be valid
wgpu::ImageCopyTexture src = {};
src.texture = texture;
encoder.CopyTextureToBuffer(&src, ...);
```
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.
Note: copyTextureToTextureInternal will be removed in favor of `WGPUDawnEncoderInternalUsageDescriptor`.

View File

@ -18,6 +18,7 @@
#include "common/Math.h" #include "common/Math.h"
#include "dawn_native/BindGroup.h" #include "dawn_native/BindGroup.h"
#include "dawn_native/Buffer.h" #include "dawn_native/Buffer.h"
#include "dawn_native/ChainUtils_autogen.h"
#include "dawn_native/CommandBuffer.h" #include "dawn_native/CommandBuffer.h"
#include "dawn_native/CommandBufferStateTracker.h" #include "dawn_native/CommandBufferStateTracker.h"
#include "dawn_native/CommandValidation.h" #include "dawn_native/CommandValidation.h"
@ -159,7 +160,8 @@ namespace dawn::native {
} }
MaybeError ValidateResolveTarget(const DeviceBase* device, MaybeError ValidateResolveTarget(const DeviceBase* device,
const RenderPassColorAttachment& colorAttachment) { const RenderPassColorAttachment& colorAttachment,
UsageValidationMode usageValidationMode) {
if (colorAttachment.resolveTarget == nullptr) { if (colorAttachment.resolveTarget == nullptr) {
return {}; return {};
} }
@ -168,7 +170,7 @@ namespace dawn::native {
const TextureViewBase* attachment = colorAttachment.view; const TextureViewBase* attachment = colorAttachment.view;
DAWN_TRY(device->ValidateObject(colorAttachment.resolveTarget)); DAWN_TRY(device->ValidateObject(colorAttachment.resolveTarget));
DAWN_TRY(ValidateCanUseAs(colorAttachment.resolveTarget->GetTexture(), DAWN_TRY(ValidateCanUseAs(colorAttachment.resolveTarget->GetTexture(),
wgpu::TextureUsage::RenderAttachment)); wgpu::TextureUsage::RenderAttachment, usageValidationMode));
DAWN_INVALID_IF( DAWN_INVALID_IF(
!attachment->GetTexture()->IsMultisampledTexture(), !attachment->GetTexture()->IsMultisampledTexture(),
@ -216,11 +218,12 @@ namespace dawn::native {
const RenderPassColorAttachment& colorAttachment, const RenderPassColorAttachment& colorAttachment,
uint32_t* width, uint32_t* width,
uint32_t* height, uint32_t* height,
uint32_t* sampleCount) { uint32_t* sampleCount,
UsageValidationMode usageValidationMode) {
TextureViewBase* attachment = colorAttachment.view; TextureViewBase* attachment = colorAttachment.view;
DAWN_TRY(device->ValidateObject(attachment)); DAWN_TRY(device->ValidateObject(attachment));
DAWN_TRY( DAWN_TRY(ValidateCanUseAs(attachment->GetTexture(),
ValidateCanUseAs(attachment->GetTexture(), wgpu::TextureUsage::RenderAttachment)); wgpu::TextureUsage::RenderAttachment, usageValidationMode));
DAWN_INVALID_IF(!(attachment->GetAspects() & Aspect::Color) || DAWN_INVALID_IF(!(attachment->GetAspects() & Aspect::Color) ||
!attachment->GetFormat().isRenderable, !attachment->GetFormat().isRenderable,
@ -241,7 +244,7 @@ namespace dawn::native {
DAWN_TRY(ValidateOrSetColorAttachmentSampleCount(attachment, sampleCount)); DAWN_TRY(ValidateOrSetColorAttachmentSampleCount(attachment, sampleCount));
DAWN_TRY(ValidateResolveTarget(device, colorAttachment)); DAWN_TRY(ValidateResolveTarget(device, colorAttachment, usageValidationMode));
DAWN_TRY(ValidateAttachmentArrayLayersAndLevelCount(attachment)); DAWN_TRY(ValidateAttachmentArrayLayersAndLevelCount(attachment));
DAWN_TRY(ValidateOrSetAttachmentSize(attachment, width, height)); DAWN_TRY(ValidateOrSetAttachmentSize(attachment, width, height));
@ -254,13 +257,14 @@ namespace dawn::native {
const RenderPassDepthStencilAttachment* depthStencilAttachment, const RenderPassDepthStencilAttachment* depthStencilAttachment,
uint32_t* width, uint32_t* width,
uint32_t* height, uint32_t* height,
uint32_t* sampleCount) { uint32_t* sampleCount,
UsageValidationMode usageValidationMode) {
DAWN_ASSERT(depthStencilAttachment != nullptr); DAWN_ASSERT(depthStencilAttachment != nullptr);
TextureViewBase* attachment = depthStencilAttachment->view; TextureViewBase* attachment = depthStencilAttachment->view;
DAWN_TRY(device->ValidateObject(attachment)); DAWN_TRY(device->ValidateObject(attachment));
DAWN_TRY( DAWN_TRY(ValidateCanUseAs(attachment->GetTexture(),
ValidateCanUseAs(attachment->GetTexture(), wgpu::TextureUsage::RenderAttachment)); wgpu::TextureUsage::RenderAttachment, usageValidationMode));
const Format& format = attachment->GetFormat(); const Format& format = attachment->GetFormat();
DAWN_INVALID_IF( DAWN_INVALID_IF(
@ -333,24 +337,25 @@ namespace dawn::native {
const RenderPassDescriptor* descriptor, const RenderPassDescriptor* descriptor,
uint32_t* width, uint32_t* width,
uint32_t* height, uint32_t* height,
uint32_t* sampleCount) { uint32_t* sampleCount,
UsageValidationMode usageValidationMode) {
DAWN_INVALID_IF( DAWN_INVALID_IF(
descriptor->colorAttachmentCount > kMaxColorAttachments, descriptor->colorAttachmentCount > kMaxColorAttachments,
"Color attachment count (%u) exceeds the maximum number of color attachments (%u).", "Color attachment count (%u) exceeds the maximum number of color attachments (%u).",
descriptor->colorAttachmentCount, kMaxColorAttachments); descriptor->colorAttachmentCount, kMaxColorAttachments);
for (uint32_t i = 0; i < descriptor->colorAttachmentCount; ++i) { for (uint32_t i = 0; i < descriptor->colorAttachmentCount; ++i) {
DAWN_TRY_CONTEXT( DAWN_TRY_CONTEXT(ValidateRenderPassColorAttachment(
ValidateRenderPassColorAttachment(device, descriptor->colorAttachments[i], device, descriptor->colorAttachments[i], width, height,
width, height, sampleCount), sampleCount, usageValidationMode),
"validating colorAttachments[%u].", i); "validating colorAttachments[%u].", i);
} }
if (descriptor->depthStencilAttachment != nullptr) { if (descriptor->depthStencilAttachment != nullptr) {
DAWN_TRY_CONTEXT( DAWN_TRY_CONTEXT(ValidateRenderPassDepthStencilAttachment(
ValidateRenderPassDepthStencilAttachment( device, descriptor->depthStencilAttachment, width, height,
device, descriptor->depthStencilAttachment, width, height, sampleCount), sampleCount, usageValidationMode),
"validating depthStencilAttachment."); "validating depthStencilAttachment.");
} }
if (descriptor->occlusionQuerySet != nullptr) { if (descriptor->occlusionQuerySet != nullptr) {
@ -468,9 +473,50 @@ namespace dawn::native {
} // namespace } // namespace
MaybeError ValidateCommandEncoderDescriptor(const DeviceBase* device,
const CommandEncoderDescriptor* descriptor) {
DAWN_TRY(ValidateSingleSType(descriptor->nextInChain,
wgpu::SType::DawnEncoderInternalUsageDescriptor));
const DawnEncoderInternalUsageDescriptor* internalUsageDesc = nullptr;
FindInChain(descriptor->nextInChain, &internalUsageDesc);
DAWN_INVALID_IF(internalUsageDesc != nullptr &&
!device->APIHasFeature(wgpu::FeatureName::DawnInternalUsages),
"%s is not available.", wgpu::FeatureName::DawnInternalUsages);
return {};
}
// static
Ref<CommandEncoder> CommandEncoder::Create(DeviceBase* device,
const CommandEncoderDescriptor* descriptor) {
return AcquireRef(new CommandEncoder(device, descriptor));
}
// static
CommandEncoder* CommandEncoder::MakeError(DeviceBase* device) {
return new CommandEncoder(device, ObjectBase::kError);
}
CommandEncoder::CommandEncoder(DeviceBase* device, const CommandEncoderDescriptor* descriptor) CommandEncoder::CommandEncoder(DeviceBase* device, const CommandEncoderDescriptor* descriptor)
: ApiObjectBase(device, descriptor->label), mEncodingContext(device, this) { : ApiObjectBase(device, descriptor->label), mEncodingContext(device, this) {
TrackInDevice(); TrackInDevice();
const DawnEncoderInternalUsageDescriptor* internalUsageDesc = nullptr;
FindInChain(descriptor->nextInChain, &internalUsageDesc);
if (internalUsageDesc != nullptr && internalUsageDesc->useInternalUsages) {
mUsageValidationMode = UsageValidationMode::Internal;
} else {
mUsageValidationMode = UsageValidationMode::Default;
}
}
CommandEncoder::CommandEncoder(DeviceBase* device, ObjectBase::ErrorTag tag)
: ApiObjectBase(device, tag),
mEncodingContext(device, this),
mUsageValidationMode(UsageValidationMode::Default) {
mEncodingContext.HandleError(DAWN_FORMAT_VALIDATION_ERROR("%s is invalid.", this));
} }
ObjectType CommandEncoder::GetType() const { ObjectType CommandEncoder::GetType() const {
@ -554,7 +600,7 @@ namespace dawn::native {
uint32_t sampleCount = 0; uint32_t sampleCount = 0;
DAWN_TRY(ValidateRenderPassDescriptor(device, descriptor, &width, &height, DAWN_TRY(ValidateRenderPassDescriptor(device, descriptor, &width, &height,
&sampleCount)); &sampleCount, mUsageValidationMode));
ASSERT(width > 0 && height > 0 && sampleCount > 0); ASSERT(width > 0 && height > 0 && sampleCount > 0);
@ -703,7 +749,8 @@ namespace dawn::native {
DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *destination, *copySize)); DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *destination, *copySize));
DAWN_TRY_CONTEXT( DAWN_TRY_CONTEXT(
ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst), ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst,
mUsageValidationMode),
"validating destination %s usage.", destination->texture); "validating destination %s usage.", destination->texture);
DAWN_TRY(ValidateTextureSampleCountInBufferCopyCommands(destination->texture)); DAWN_TRY(ValidateTextureSampleCountInBufferCopyCommands(destination->texture));
@ -757,7 +804,8 @@ namespace dawn::native {
[&](CommandAllocator* allocator) -> MaybeError { [&](CommandAllocator* allocator) -> MaybeError {
if (GetDevice()->IsValidationEnabled()) { if (GetDevice()->IsValidationEnabled()) {
DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *source, *copySize)); DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *source, *copySize));
DAWN_TRY_CONTEXT(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc), DAWN_TRY_CONTEXT(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc,
mUsageValidationMode),
"validating source %s usage.", source->texture); "validating source %s usage.", source->texture);
DAWN_TRY(ValidateTextureSampleCountInBufferCopyCommands(source->texture)); DAWN_TRY(ValidateTextureSampleCountInBufferCopyCommands(source->texture));
DAWN_TRY(ValidateTextureDepthStencilToBufferCopyRestrictions(*source)); DAWN_TRY(ValidateTextureDepthStencilToBufferCopyRestrictions(*source));
@ -846,14 +894,15 @@ namespace dawn::native {
// For internal usages (CopyToCopyInternal) we don't care if the user has added // For internal usages (CopyToCopyInternal) we don't care if the user has added
// CopySrc as a usage for this texture, but we will always add it internally. // CopySrc as a usage for this texture, but we will always add it internally.
if (Internal) { if (Internal) {
DAWN_TRY( DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc,
ValidateInternalCanUseAs(source->texture, wgpu::TextureUsage::CopySrc)); UsageValidationMode::Internal));
DAWN_TRY(ValidateInternalCanUseAs(destination->texture, DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst,
wgpu::TextureUsage::CopyDst)); UsageValidationMode::Internal));
} else { } else {
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc)); DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc,
DAWN_TRY( mUsageValidationMode));
ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst)); DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst,
mUsageValidationMode));
} }
mTopLevelTextures.insert(source->texture); mTopLevelTextures.insert(source->texture);

View File

@ -26,9 +26,16 @@
namespace dawn::native { namespace dawn::native {
enum class UsageValidationMode;
MaybeError ValidateCommandEncoderDescriptor(const DeviceBase* device,
const CommandEncoderDescriptor* descriptor);
class CommandEncoder final : public ApiObjectBase { class CommandEncoder final : public ApiObjectBase {
public: public:
CommandEncoder(DeviceBase* device, const CommandEncoderDescriptor* descriptor); static Ref<CommandEncoder> Create(DeviceBase* device,
const CommandEncoderDescriptor* descriptor);
static CommandEncoder* MakeError(DeviceBase* device);
ObjectType GetType() const override; ObjectType GetType() const override;
@ -80,6 +87,9 @@ namespace dawn::native {
CommandBufferBase* APIFinish(const CommandBufferDescriptor* descriptor = nullptr); CommandBufferBase* APIFinish(const CommandBufferDescriptor* descriptor = nullptr);
private: private:
CommandEncoder(DeviceBase* device, const CommandEncoderDescriptor* descriptor);
CommandEncoder(DeviceBase* device, ObjectBase::ErrorTag tag);
void DestroyImpl() override; void DestroyImpl() override;
ResultOrError<Ref<CommandBufferBase>> FinishInternal( ResultOrError<Ref<CommandBufferBase>> FinishInternal(
const CommandBufferDescriptor* descriptor); const CommandBufferDescriptor* descriptor);
@ -100,6 +110,8 @@ namespace dawn::native {
std::set<QuerySetBase*> mUsedQuerySets; std::set<QuerySetBase*> mUsedQuerySets;
uint64_t mDebugGroupStackSize = 0; uint64_t mDebugGroupStackSize = 0;
UsageValidationMode mUsageValidationMode;
}; };
} // namespace dawn::native } // namespace dawn::native

View File

@ -447,19 +447,21 @@ namespace dawn::native {
return ValidateTextureToTextureCopyCommonRestrictions(src, dst, copySize); return ValidateTextureToTextureCopyCommonRestrictions(src, dst, copySize);
} }
MaybeError ValidateCanUseAs(const TextureBase* texture, wgpu::TextureUsage usage) { MaybeError ValidateCanUseAs(const TextureBase* texture,
wgpu::TextureUsage usage,
UsageValidationMode mode) {
ASSERT(wgpu::HasZeroOrOneBits(usage)); ASSERT(wgpu::HasZeroOrOneBits(usage));
DAWN_INVALID_IF(!(texture->GetUsage() & usage), "%s usage (%s) doesn't include %s.", switch (mode) {
texture, texture->GetUsage(), usage); case UsageValidationMode::Default:
DAWN_INVALID_IF(!(texture->GetUsage() & usage), "%s usage (%s) doesn't include %s.",
return {}; texture, texture->GetUsage(), usage);
} break;
case UsageValidationMode::Internal:
MaybeError ValidateInternalCanUseAs(const TextureBase* texture, wgpu::TextureUsage usage) { DAWN_INVALID_IF(!(texture->GetInternalUsage() & usage),
ASSERT(wgpu::HasZeroOrOneBits(usage)); "%s internal usage (%s) doesn't include %s.", texture,
DAWN_INVALID_IF(!(texture->GetInternalUsage() & usage), texture->GetInternalUsage(), usage);
"%s internal usage (%s) doesn't include %s.", texture, break;
texture->GetInternalUsage(), usage); }
return {}; return {};
} }
@ -468,7 +470,6 @@ namespace dawn::native {
ASSERT(wgpu::HasZeroOrOneBits(usage)); ASSERT(wgpu::HasZeroOrOneBits(usage));
DAWN_INVALID_IF(!(buffer->GetUsage() & usage), "%s usage (%s) doesn't include %s.", buffer, DAWN_INVALID_IF(!(buffer->GetUsage() & usage), "%s usage (%s) doesn't include %s.", buffer,
buffer->GetUsage(), usage); buffer->GetUsage(), usage);
return {}; return {};
} }

View File

@ -73,10 +73,14 @@ namespace dawn::native {
const ImageCopyTexture& dst, const ImageCopyTexture& dst,
const Extent3D& copySize); const Extent3D& copySize);
MaybeError ValidateCanUseAs(const TextureBase* texture, wgpu::TextureUsage usage); enum class UsageValidationMode {
Default,
MaybeError ValidateInternalCanUseAs(const TextureBase* texture, wgpu::TextureUsage usage); Internal,
};
MaybeError ValidateCanUseAs(const TextureBase* texture,
wgpu::TextureUsage usage,
UsageValidationMode mode);
MaybeError ValidateCanUseAs(const BufferBase* buffer, wgpu::BufferUsage usage); MaybeError ValidateCanUseAs(const BufferBase* buffer, wgpu::BufferUsage usage);
} // namespace dawn::native } // namespace dawn::native

View File

@ -350,11 +350,15 @@ namespace dawn::native {
"not 1.", "not 1.",
source->texture->GetSampleCount(), destination->texture->GetSampleCount()); source->texture->GetSampleCount(), destination->texture->GetSampleCount());
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc)); DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc,
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::TextureBinding)); UsageValidationMode::Default));
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::TextureBinding,
UsageValidationMode::Default));
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst)); DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst,
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::RenderAttachment)); UsageValidationMode::Default));
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::RenderAttachment,
UsageValidationMode::Default));
DAWN_TRY(ValidateCopyTextureFormatConversion(source->texture->GetFormat().format, DAWN_TRY(ValidateCopyTextureFormatConversion(source->texture->GetFormat().format,
destination->texture->GetFormat().format)); destination->texture->GetFormat().format));

View File

@ -953,7 +953,13 @@ namespace dawn::native {
if (descriptor == nullptr) { if (descriptor == nullptr) {
descriptor = &defaultDescriptor; descriptor = &defaultDescriptor;
} }
return new CommandEncoder(this, descriptor);
Ref<CommandEncoder> result;
if (ConsumedError(CreateCommandEncoder(descriptor), &result,
"calling %s.CreateCommandEncoder(%s).", this, descriptor)) {
return CommandEncoder::MakeError(this);
}
return result.Detach();
} }
ComputePipelineBase* DeviceBase::APICreateComputePipeline( ComputePipelineBase* DeviceBase::APICreateComputePipeline(
const ComputePipelineDescriptor* descriptor) { const ComputePipelineDescriptor* descriptor) {
@ -1313,6 +1319,15 @@ namespace dawn::native {
return AddOrGetCachedComputePipeline(std::move(uninitializedComputePipeline)); return AddOrGetCachedComputePipeline(std::move(uninitializedComputePipeline));
} }
ResultOrError<Ref<CommandEncoder>> DeviceBase::CreateCommandEncoder(
const CommandEncoderDescriptor* descriptor) {
DAWN_TRY(ValidateIsAlive());
if (IsValidationEnabled()) {
DAWN_TRY(ValidateCommandEncoderDescriptor(this, descriptor));
}
return CommandEncoder::Create(this, descriptor);
}
MaybeError DeviceBase::CreateComputePipelineAsync( MaybeError DeviceBase::CreateComputePipelineAsync(
const ComputePipelineDescriptor* descriptor, const ComputePipelineDescriptor* descriptor,
WGPUCreateComputePipelineAsyncCallback callback, WGPUCreateComputePipelineAsyncCallback callback,

View File

@ -198,6 +198,8 @@ namespace dawn::native {
const BindGroupLayoutDescriptor* descriptor, const BindGroupLayoutDescriptor* descriptor,
bool allowInternalBinding = false); bool allowInternalBinding = false);
ResultOrError<Ref<BufferBase>> CreateBuffer(const BufferDescriptor* descriptor); ResultOrError<Ref<BufferBase>> CreateBuffer(const BufferDescriptor* descriptor);
ResultOrError<Ref<CommandEncoder>> CreateCommandEncoder(
const CommandEncoderDescriptor* descriptor);
ResultOrError<Ref<ComputePipelineBase>> CreateComputePipeline( ResultOrError<Ref<ComputePipelineBase>> CreateComputePipeline(
const ComputePipelineDescriptor* descriptor); const ComputePipelineDescriptor* descriptor);
MaybeError CreateComputePipelineAsync( MaybeError CreateComputePipelineAsync(

View File

@ -16,10 +16,11 @@
#include "utils/WGPUHelpers.h" #include "utils/WGPUHelpers.h"
class TextureInternalUsageValidationDisabledTest : public ValidationTest {}; class InternalUsageValidationDisabledTest : public ValidationTest {};
// Test that using the feature is an error if it is not enabled // Test that using DawnTextureInternalUsageDescriptor is an error if DawnInternalUsages is not
TEST_F(TextureInternalUsageValidationDisabledTest, RequiresFeature) { // enabled
TEST_F(InternalUsageValidationDisabledTest, TextureDescriptorRequiresFeature) {
wgpu::TextureDescriptor textureDesc = {}; wgpu::TextureDescriptor textureDesc = {};
textureDesc.size = {1, 1}; textureDesc.size = {1, 1};
textureDesc.usage = wgpu::TextureUsage::CopySrc; textureDesc.usage = wgpu::TextureUsage::CopySrc;
@ -42,6 +43,26 @@ TEST_F(TextureInternalUsageValidationDisabledTest, RequiresFeature) {
ASSERT_DEVICE_ERROR(device.CreateTexture(&textureDesc)); ASSERT_DEVICE_ERROR(device.CreateTexture(&textureDesc));
} }
// Test that using DawnEncoderInternalUsageDescriptor is an error if DawnInternalUsages is not
// enabled
TEST_F(InternalUsageValidationDisabledTest, CommandEncoderDescriptorRequiresFeature) {
wgpu::CommandEncoderDescriptor encoderDesc = {};
// Control case: Normal encoder creation works
device.CreateCommandEncoder(&encoderDesc);
wgpu::DawnEncoderInternalUsageDescriptor internalDesc = {};
encoderDesc.nextInChain = &internalDesc;
// Error with chained DawnEncoderInternalUsageDescriptor.
ASSERT_DEVICE_ERROR(wgpu::CommandEncoder encoder = device.CreateCommandEncoder(&encoderDesc));
// Check that the encoder records that it is invalid, and not any other errors.
encoder.InjectValidationError("injected error");
ASSERT_DEVICE_ERROR(encoder.Finish(),
testing::HasSubstr("[Invalid CommandEncoder] is invalid"));
}
class TextureInternalUsageValidationTest : public ValidationTest { class TextureInternalUsageValidationTest : public ValidationTest {
WGPUDevice CreateTestDevice() override { WGPUDevice CreateTestDevice() override {
wgpu::DeviceDescriptor descriptor; wgpu::DeviceDescriptor descriptor;
@ -117,7 +138,7 @@ TEST_F(TextureInternalUsageValidationTest, UsageValidation) {
// Test that internal usage does not add to the validated usage // Test that internal usage does not add to the validated usage
// for command encoding // for command encoding
// This test also test the internal copy // This test also test the internal copy
TEST_F(TextureInternalUsageValidationTest, CommandValidation) { TEST_F(TextureInternalUsageValidationTest, DeprecatedCommandValidation) {
wgpu::TextureDescriptor textureDesc = {}; wgpu::TextureDescriptor textureDesc = {};
textureDesc.size = {1, 1}; textureDesc.size = {1, 1};
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm; textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
@ -182,3 +203,96 @@ TEST_F(TextureInternalUsageValidationTest, CommandValidation) {
encoder.Finish(); encoder.Finish();
} }
} }
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());
}
// Invalid: src internal -> dst, with internal descriptor, but useInternalUsages set to false.
{
wgpu::ImageCopyTexture srcImageCopyTexture =
utils::CreateImageCopyTexture(srcInternal, 0, {0, 0});
wgpu::ImageCopyTexture dstImageCopyTexture = utils::CreateImageCopyTexture(dst, 0, {0, 0});
wgpu::Extent3D extent3D = {1, 1};
wgpu::CommandEncoderDescriptor encoderDesc = {};
wgpu::DawnEncoderInternalUsageDescriptor internalDesc = {};
internalDesc.useInternalUsages = false;
encoderDesc.nextInChain = &internalDesc;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(&encoderDesc);
encoder.CopyTextureToTexture(&srcImageCopyTexture, &dstImageCopyTexture, &extent3D);
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Control with internal copy: 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::CommandEncoderDescriptor encoderDesc = {};
wgpu::DawnEncoderInternalUsageDescriptor internalDesc = {};
internalDesc.useInternalUsages = true;
encoderDesc.nextInChain = &internalDesc;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(&encoderDesc);
encoder.CopyTextureToTexture(&srcImageCopyTexture, &dstImageCopyTexture, &extent3D);
encoder.Finish();
}
// Valid with internal copy: 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::CommandEncoderDescriptor encoderDesc = {};
wgpu::DawnEncoderInternalUsageDescriptor internalDesc = {};
internalDesc.useInternalUsages = true;
encoderDesc.nextInChain = &internalDesc;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(&encoderDesc);
encoder.CopyTextureToTexture(&srcImageCopyTexture, &dstImageCopyTexture, &extent3D);
encoder.Finish();
}
}