Reland "Add CopyExternalTextureForBrowser()"

This is a reland of commit f392c38b67

The new added structure ImageCopyExternalTexture used in dawn only. Adding
tags : ["dawn"] to fix compile error.

Original change's description:
> Add CopyExternalTextureForBrowser()
>
> This API accept ExternalTexture object as copy source and a dawn 2D texture
> as destination. It has similar functions as CopyTextureForBrowser().
> The API is used to support cases that source images are multi-planar format
> and want to do conversion and uploading to a dawn 2D texture.
>
> Bug: chromium:1361363
> Change-Id: Ie390acfb95b47d417f4a8faa2d1e19163d549154
> Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/105880
> Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
> Reviewed-by: Austin Eng <enga@chromium.org>
> Reviewed-by: Corentin Wallez <cwallez@chromium.org>

Bug: chromium:1361363
Change-Id: I213c3dc7fe81ccc35050592e491995d0d5425f6e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/106883
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
This commit is contained in:
Yan,Shaobo 2022-10-26 00:58:46 +00:00 committed by Dawn LUCI CQ
parent 0640c81073
commit b4d8c8012b
16 changed files with 1167 additions and 237 deletions

View File

@ -916,7 +916,6 @@
"category": "structure",
"extensible": "in",
"tags": ["dawn"],
"_TODO": "support number as length input",
"members": [
{"name": "flip y", "type": "bool", "default": "false"},
{"name": "needs color space conversion", "type": "bool", "default": "false"},
@ -1367,7 +1366,6 @@
"category": "structure",
"extensible": "in",
"tags": ["dawn"],
"_TODO": "crbug.com/1316671: Mark 'visible rect' as must have after chromium side changes landed",
"members": [
{"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
{"name": "plane 0", "type": "texture view"},
@ -1440,6 +1438,15 @@
{"name": "aspect", "type": "texture aspect", "default": "all"}
]
},
"image copy external texture": {
"category": "structure",
"extensible": "in",
"tags": ["dawn"],
"members": [
{"name": "external texture", "type": "external texture"},
{"name": "origin", "type": "origin 3D"}
]
},
"index format": {
"category": "enum",
"values": [
@ -1721,6 +1728,17 @@
{"name": "options", "type": "copy texture for browser options", "annotation": "const*"}
]
},
{
"name": "copy external texture for browser",
"extensible": "in",
"tags": ["dawn"],
"args": [
{"name": "source", "type": "image copy external texture", "annotation": "const*"},
{"name": "destination", "type": "image copy texture", "annotation": "const*"},
{"name": "copy size", "type": "extent 3D", "annotation": "const*"},
{"name": "options", "type": "copy texture for browser options", "annotation": "const*"}
]
},
{
"name": "set label",
"returns": "void",

View File

@ -25,6 +25,7 @@
#include "dawn/native/CommandEncoder.h"
#include "dawn/native/CommandValidation.h"
#include "dawn/native/Device.h"
#include "dawn/native/ExternalTexture.h"
#include "dawn/native/InternalPipelineStore.h"
#include "dawn/native/Queue.h"
#include "dawn/native/RenderPassEncoder.h"
@ -36,9 +37,8 @@
namespace dawn::native {
namespace {
static const char sCopyTextureForBrowserShader[] = R"(
struct GammaTransferParams {
static const char sCopyForBrowserShader[] = R"(
struct GammaTransferParamsInternal {
G: f32,
A: f32,
B: f32,
@ -49,15 +49,15 @@ static const char sCopyTextureForBrowserShader[] = R"(
padding: u32,
};
struct Uniforms { // offset align size
scale: vec2<f32>, // 0 8 8
offset: vec2<f32>, // 8 8 8
steps_mask: u32, // 16 4 4
// implicit padding; // 20 12
conversion_matrix: mat3x3<f32>, // 32 16 48
gamma_decoding_params: GammaTransferParams, // 80 4 32
gamma_encoding_params: GammaTransferParams, // 112 4 32
gamma_decoding_for_dst_srgb_params: GammaTransferParams, // 144 4 32
struct Uniforms { // offset align size
scale: vec2<f32>, // 0 8 8
offset: vec2<f32>, // 8 8 8
steps_mask: u32, // 16 4 4
// implicit padding; // 20 12
conversion_matrix: mat3x3<f32>, // 32 16 48
gamma_decoding_params: GammaTransferParamsInternal, // 80 4 32
gamma_encoding_params: GammaTransferParamsInternal, // 112 4 32
gamma_decoding_for_dst_srgb_params: GammaTransferParamsInternal, // 144 4 32
};
@binding(0) @group(0) var<uniform> uniforms : Uniforms;
@ -75,7 +75,7 @@ static const char sCopyTextureForBrowserShader[] = R"(
// nonlinear = pow(A * x + B, G) + E
// (https://source.chromium.org/chromium/chromium/src/+/main:ui/gfx/color_transform.cc;l=541)
// Expand the equation with sign() to make it handle all gamma conversions.
fn gamma_conversion(v: f32, params: GammaTransferParams) -> f32 {
fn gamma_conversion(v: f32, params: GammaTransferParamsInternal) -> f32 {
// Linear part: C * x + F
if (abs(v) < params.D) {
return sign(v) * (params.C * abs(v) + params.F);
@ -121,24 +121,23 @@ static const char sCopyTextureForBrowserShader[] = R"(
}
@binding(1) @group(0) var mySampler: sampler;
@binding(2) @group(0) var myTexture: texture_2d<f32>;
@fragment
fn fs_main(
@location(0) texcoord : vec2<f32>
) -> @location(0) vec4<f32> {
// Clamp the texcoord and discard the out-of-bound pixels.
// Resource used in copyTexture entry point only.
@binding(2) @group(0) var mySourceTexture: texture_2d<f32>;
// Resource used in copyExternalTexture entry point only.
@binding(2) @group(0) var mySourceExternalTexture: texture_external;
fn discardIfOutsideOfCopy(texcoord : vec2<f32>) {
var clampedTexcoord =
clamp(texcoord, vec2<f32>(0.0, 0.0), vec2<f32>(1.0, 1.0));
// Swizzling of texture formats when sampling / rendering is handled by the
// hardware so we don't need special logic in this shader. This is covered by tests.
var color = textureSample(myTexture, mySampler, texcoord);
if (!all(clampedTexcoord == texcoord)) {
discard;
}
}
fn transform(srcColor : vec4<f32>) -> vec4<f32> {
var color = srcColor;
let kUnpremultiplyStep = 0x01u;
let kDecodeToLinearStep = 0x02u;
let kConvertToDstGamutStep = 0x04u;
@ -203,11 +202,33 @@ static const char sCopyTextureForBrowserShader[] = R"(
return color;
}
@fragment
fn copyTexture(@location(0) texcoord : vec2<f32>
) -> @location(0) vec4<f32> {
var color = textureSample(mySourceTexture, mySampler, texcoord);
// TODO(crbug.com/tint/1723): Discard before sampling should be valid.
discardIfOutsideOfCopy(texcoord);
return transform(color);
}
@fragment
fn copyExternalTexture(@location(0) texcoord : vec2<f32>
) -> @location(0) vec4<f32> {
var color = textureSampleBaseClampToEdge(mySourceExternalTexture, mySampler, texcoord);
// TODO(crbug.com/tint/1723): Discard before sampling should be valid.
discardIfOutsideOfCopy(texcoord);
return transform(color);
}
)";
// Follow the same order of skcms_TransferFunction
// https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/include/third_party/skcms/skcms.h;l=46;
struct GammaTransferParams {
struct GammaTransferParamsInternal {
float G = 0.0;
float A = 0.0;
float B = 0.0;
@ -226,16 +247,22 @@ struct Uniform {
uint32_t stepsMask = 0;
const std::array<uint32_t, 3> padding = {}; // 12 bytes padding
std::array<float, 12> conversionMatrix = {};
GammaTransferParams gammaDecodingParams = {};
GammaTransferParams gammaEncodingParams = {};
GammaTransferParams gammaDecodingForDstSrgbParams = {};
GammaTransferParamsInternal gammaDecodingParams = {};
GammaTransferParamsInternal gammaEncodingParams = {};
GammaTransferParamsInternal gammaDecodingForDstSrgbParams = {};
};
static_assert(sizeof(Uniform) == 176);
enum class SourceTextureType { Texture2D, ExternalTexture };
struct TextureInfo {
Origin3D origin;
Extent3D size;
};
// TODO(crbug.com/dawn/856): Expand copyTextureForBrowser to support any
// non-depth, non-stencil, non-compressed texture format pair copy.
MaybeError ValidateCopyTextureFormatConversion(const wgpu::TextureFormat srcFormat,
const wgpu::TextureFormat dstFormat) {
MaybeError ValidateCopyTextureSourceFormat(const wgpu::TextureFormat srcFormat) {
switch (srcFormat) {
case wgpu::TextureFormat::BGRA8Unorm:
case wgpu::TextureFormat::RGBA8Unorm:
@ -245,6 +272,10 @@ MaybeError ValidateCopyTextureFormatConversion(const wgpu::TextureFormat srcForm
return DAWN_VALIDATION_ERROR("Source texture format (%s) is not supported.", srcFormat);
}
return {};
}
MaybeError ValidateCopyForBrowserDestinationFormat(const wgpu::TextureFormat dstFormat) {
switch (dstFormat) {
case wgpu::TextureFormat::R8Unorm:
case wgpu::TextureFormat::R16Float:
@ -268,7 +299,8 @@ MaybeError ValidateCopyTextureFormatConversion(const wgpu::TextureFormat srcForm
return {};
}
RenderPipelineBase* GetCachedPipeline(InternalPipelineStore* store, wgpu::TextureFormat dstFormat) {
RenderPipelineBase* GetCachedCopyTexturePipeline(InternalPipelineStore* store,
wgpu::TextureFormat dstFormat) {
auto pipeline = store->copyTextureForBrowserPipelines.find(dstFormat);
if (pipeline != store->copyTextureForBrowserPipelines.end()) {
return pipeline->second.Get();
@ -276,120 +308,92 @@ RenderPipelineBase* GetCachedPipeline(InternalPipelineStore* store, wgpu::Textur
return nullptr;
}
RenderPipelineBase* GetCachedCopyExternalTexturePipeline(InternalPipelineStore* store,
wgpu::TextureFormat dstFormat) {
auto pipeline = store->copyExternalTextureForBrowserPipelines.find(dstFormat);
if (pipeline != store->copyExternalTextureForBrowserPipelines.end()) {
return pipeline->second.Get();
}
return nullptr;
}
ResultOrError<Ref<RenderPipelineBase>> CreateCopyForBrowserPipeline(
DeviceBase* device,
wgpu::TextureFormat dstFormat,
ShaderModuleBase* shaderModule,
const char* fragmentEntryPoint) {
// Prepare vertex stage.
VertexState vertex = {};
vertex.module = shaderModule;
vertex.entryPoint = "vs_main";
// Prepare frgament stage.
FragmentState fragment = {};
fragment.module = shaderModule;
fragment.entryPoint = fragmentEntryPoint;
// Prepare color state.
ColorTargetState target = {};
target.format = dstFormat;
// Create RenderPipeline.
RenderPipelineDescriptor renderPipelineDesc = {};
// Generate the layout based on shader modules.
renderPipelineDesc.layout = nullptr;
renderPipelineDesc.vertex = vertex;
renderPipelineDesc.fragment = &fragment;
renderPipelineDesc.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
fragment.targetCount = 1;
fragment.targets = &target;
return device->CreateRenderPipeline(&renderPipelineDesc);
}
ResultOrError<ShaderModuleBase*> GetOrCreateCopyForBrowserShaderModule(
DeviceBase* device,
InternalPipelineStore* store) {
if (store->copyForBrowser == nullptr) {
DAWN_TRY_ASSIGN(store->copyForBrowser,
utils::CreateShaderModule(device, sCopyForBrowserShader));
}
return store->copyForBrowser.Get();
}
ResultOrError<RenderPipelineBase*> GetOrCreateCopyTextureForBrowserPipeline(
DeviceBase* device,
wgpu::TextureFormat dstFormat) {
InternalPipelineStore* store = device->GetInternalPipelineStore();
if (GetCachedPipeline(store, dstFormat) == nullptr) {
// Create vertex shader module if not cached before.
if (store->copyTextureForBrowser == nullptr) {
DAWN_TRY_ASSIGN(store->copyTextureForBrowser,
utils::CreateShaderModule(device, sCopyTextureForBrowserShader));
}
ShaderModuleBase* shaderModule = store->copyTextureForBrowser.Get();
// Prepare vertex stage.
VertexState vertex = {};
vertex.module = shaderModule;
vertex.entryPoint = "vs_main";
// Prepare frgament stage.
FragmentState fragment = {};
fragment.module = shaderModule;
fragment.entryPoint = "fs_main";
// Prepare color state.
ColorTargetState target = {};
target.format = dstFormat;
// Create RenderPipeline.
RenderPipelineDescriptor renderPipelineDesc = {};
// Generate the layout based on shader modules.
renderPipelineDesc.layout = nullptr;
renderPipelineDesc.vertex = vertex;
renderPipelineDesc.fragment = &fragment;
renderPipelineDesc.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
fragment.targetCount = 1;
fragment.targets = &target;
if (GetCachedCopyTexturePipeline(store, dstFormat) == nullptr) {
ShaderModuleBase* shaderModule;
DAWN_TRY_ASSIGN(shaderModule, GetOrCreateCopyForBrowserShaderModule(device, store));
Ref<RenderPipelineBase> pipeline;
DAWN_TRY_ASSIGN(pipeline, device->CreateRenderPipeline(&renderPipelineDesc));
DAWN_TRY_ASSIGN(
pipeline, CreateCopyForBrowserPipeline(device, dstFormat, shaderModule, "copyTexture"));
store->copyTextureForBrowserPipelines.insert({dstFormat, std::move(pipeline)});
}
return GetCachedPipeline(store, dstFormat);
return GetCachedCopyTexturePipeline(store, dstFormat);
}
} // anonymous namespace
MaybeError ValidateCopyTextureForBrowser(DeviceBase* device,
const ImageCopyTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options) {
DAWN_TRY(device->ValidateObject(source->texture));
DAWN_TRY(device->ValidateObject(destination->texture));
DAWN_INVALID_IF(source->texture->GetTextureState() == TextureBase::TextureState::Destroyed,
"Source texture %s is destroyed.", source->texture);
DAWN_INVALID_IF(destination->texture->GetTextureState() == TextureBase::TextureState::Destroyed,
"Destination texture %s is destroyed.", destination->texture);
DAWN_TRY_CONTEXT(ValidateImageCopyTexture(device, *source, *copySize),
"validating the ImageCopyTexture for the source");
DAWN_TRY_CONTEXT(ValidateImageCopyTexture(device, *destination, *copySize),
"validating the ImageCopyTexture for the destination");
DAWN_TRY_CONTEXT(ValidateTextureCopyRange(device, *source, *copySize),
"validating that the copy fits in the source");
DAWN_TRY_CONTEXT(ValidateTextureCopyRange(device, *destination, *copySize),
"validating that the copy fits in the destination");
DAWN_TRY(ValidateTextureToTextureCopyCommonRestrictions(*source, *destination, *copySize));
DAWN_INVALID_IF(source->origin.z > 0, "Source has a non-zero z origin (%u).", source->origin.z);
DAWN_INVALID_IF(copySize->depthOrArrayLayers > 1, "Copy is for more than one array layer (%u)",
copySize->depthOrArrayLayers);
DAWN_INVALID_IF(
source->texture->GetSampleCount() > 1 || destination->texture->GetSampleCount() > 1,
"The source texture sample count (%u) or the destination texture sample count (%u) is "
"not 1.",
source->texture->GetSampleCount(), destination->texture->GetSampleCount());
DAWN_INVALID_IF(
options->internalUsage && !device->HasFeature(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));
DAWN_INVALID_IF(options->nextInChain != nullptr, "nextInChain must be nullptr");
DAWN_TRY(ValidateAlphaMode(options->srcAlphaMode));
DAWN_TRY(ValidateAlphaMode(options->dstAlphaMode));
if (options->needsColorSpaceConversion) {
DAWN_INVALID_IF(options->srcTransferFunctionParameters == nullptr,
"srcTransferFunctionParameters is nullptr when doing color conversion");
DAWN_INVALID_IF(options->conversionMatrix == nullptr,
"conversionMatrix is nullptr when doing color conversion");
DAWN_INVALID_IF(options->dstTransferFunctionParameters == nullptr,
"dstTransferFunctionParameters is nullptr when doing color conversion");
ResultOrError<RenderPipelineBase*> GetOrCreateCopyExternalTextureForBrowserPipeline(
DeviceBase* device,
wgpu::TextureFormat dstFormat) {
InternalPipelineStore* store = device->GetInternalPipelineStore();
if (GetCachedCopyExternalTexturePipeline(store, dstFormat) == nullptr) {
ShaderModuleBase* shaderModule;
DAWN_TRY_ASSIGN(shaderModule, GetOrCreateCopyForBrowserShaderModule(device, store));
Ref<RenderPipelineBase> pipeline;
DAWN_TRY_ASSIGN(pipeline, CreateCopyForBrowserPipeline(device, dstFormat, shaderModule,
"copyExternalTexture"));
store->copyExternalTextureForBrowserPipelines.insert({dstFormat, std::move(pipeline)});
}
return {};
return GetCachedCopyExternalTexturePipeline(store, dstFormat);
}
// Whether the format of dst texture of CopyTextureForBrowser() is srgb or non-srgb.
@ -403,11 +407,14 @@ bool IsSrgbDstFormat(wgpu::TextureFormat format) {
}
}
MaybeError DoCopyTextureForBrowser(DeviceBase* device,
const ImageCopyTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options) {
template <typename T>
MaybeError DoCopyForBrowser(DeviceBase* device,
const TextureInfo* sourceInfo,
T* sourceResource,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options,
RenderPipelineBase* pipeline) {
// TODO(crbug.com/dawn/856): In D3D12 and Vulkan, compatible texture format can directly
// copy to each other. This can be a potential fast path.
@ -416,23 +423,16 @@ MaybeError DoCopyTextureForBrowser(DeviceBase* device,
return {};
}
bool isSrgbDstFormat = IsSrgbDstFormat(destination->texture->GetFormat().format);
RenderPipelineBase* pipeline;
DAWN_TRY_ASSIGN(pipeline, GetOrCreateCopyTextureForBrowserPipeline(
device, destination->texture->GetFormat().format));
// Prepare bind group layout.
Ref<BindGroupLayoutBase> layout;
DAWN_TRY_ASSIGN(layout, pipeline->GetBindGroupLayout(0));
Extent3D srcTextureSize = source->texture->GetSize();
// Prepare binding 0 resource: uniform buffer.
Uniform uniformData = {
copySize->width / static_cast<float>(srcTextureSize.width),
copySize->height / static_cast<float>(srcTextureSize.height), // scale
source->origin.x / static_cast<float>(srcTextureSize.width),
source->origin.y / static_cast<float>(srcTextureSize.height) // offset
copySize->width / static_cast<float>(sourceInfo->size.width),
copySize->height / static_cast<float>(sourceInfo->size.height), // scale
sourceInfo->origin.x / static_cast<float>(sourceInfo->size.width),
sourceInfo->origin.y / static_cast<float>(sourceInfo->size.height) // offset
};
// Handle flipY. FlipY here means we flip the source texture firstly and then
@ -440,7 +440,7 @@ MaybeError DoCopyTextureForBrowser(DeviceBase* device,
// need to unpack the flip.
if (options->flipY) {
uniformData.scaleY *= -1.0;
uniformData.offsetY += copySize->height / static_cast<float>(srcTextureSize.height);
uniformData.offsetY += copySize->height / static_cast<float>(sourceInfo->size.height);
}
uint32_t stepsMask = 0u;
@ -528,6 +528,7 @@ MaybeError DoCopyTextureForBrowser(DeviceBase* device,
// and use it as render attachment when possible.
// TODO(crbug.com/dawn/1195): Opt the condition for this extra step. It is possible to
// bypass this extra step in some cases.
bool isSrgbDstFormat = IsSrgbDstFormat(destination->texture->GetFormat().format);
if (isSrgbDstFormat) {
stepsMask |= kDecodeForSrgbDstFormat;
// Get gamma-linear conversion params from https://en.wikipedia.org/wiki/SRGB with some
@ -536,6 +537,7 @@ MaybeError DoCopyTextureForBrowser(DeviceBase* device,
2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 4.045e-02, 0.0, 0.0};
}
// Upload uniform data
uniformData.stepsMask = stepsMask;
Ref<BufferBase> uniformBuffer;
@ -550,23 +552,13 @@ MaybeError DoCopyTextureForBrowser(DeviceBase* device,
Ref<SamplerBase> sampler;
DAWN_TRY_ASSIGN(sampler, device->CreateSampler(&samplerDesc));
// Prepare binding 2 resource: sampled texture
TextureViewDescriptor srcTextureViewDesc = {};
srcTextureViewDesc.dimension = wgpu::TextureViewDimension::e2D;
srcTextureViewDesc.baseMipLevel = source->mipLevel;
srcTextureViewDesc.mipLevelCount = 1;
srcTextureViewDesc.arrayLayerCount = 1;
Ref<TextureViewBase> srcTextureView;
DAWN_TRY_ASSIGN(srcTextureView,
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}}, mode));
{{0, uniformBuffer}, {1, sampler}, {2, sourceResource}}, mode));
// Create command encoder.
CommandEncoderDescriptor commandEncoderDesc;
@ -621,4 +613,166 @@ MaybeError DoCopyTextureForBrowser(DeviceBase* device,
return {};
}
MaybeError ValidateCopyForBrowserCommonRestrictions(DeviceBase* device,
const ImageCopyTexture& destination,
const Extent3D& copySize,
const CopyTextureForBrowserOptions& options) {
DAWN_TRY(device->ValidateObject(destination.texture));
DAWN_INVALID_IF(destination.texture->GetTextureState() == TextureBase::TextureState::Destroyed,
"Destination texture %s is destroyed.", destination.texture);
DAWN_TRY_CONTEXT(ValidateImageCopyTexture(device, destination, copySize),
"validating the ImageCopyTexture for the destination");
DAWN_TRY_CONTEXT(ValidateTextureCopyRange(device, destination, copySize),
"validating that the copy fits in the destination");
UsageValidationMode mode =
options.internalUsage ? UsageValidationMode::Internal : UsageValidationMode::Default;
DAWN_TRY(ValidateCanUseAs(destination.texture, wgpu::TextureUsage::CopyDst, mode));
DAWN_TRY(ValidateCanUseAs(destination.texture, wgpu::TextureUsage::RenderAttachment, mode));
DAWN_INVALID_IF(copySize.depthOrArrayLayers > 1, "Copy is for more than one array layer (%u)",
copySize.depthOrArrayLayers);
DAWN_INVALID_IF(destination.texture->GetSampleCount() > 1,
"The destination texture sample count (%u) is not 1.",
destination.texture->GetSampleCount());
DAWN_TRY(ValidateCopyForBrowserDestinationFormat(destination.texture->GetFormat().format));
// The valid destination formats are all color formats.
DAWN_INVALID_IF(
destination.aspect != wgpu::TextureAspect::All,
"Destination %s aspect (%s) doesn't select all the aspects of the destination format.",
destination.texture, destination.aspect);
DAWN_INVALID_IF(options.nextInChain != nullptr, "nextInChain must be nullptr");
DAWN_TRY(ValidateAlphaMode(options.srcAlphaMode));
DAWN_TRY(ValidateAlphaMode(options.dstAlphaMode));
if (options.needsColorSpaceConversion) {
DAWN_INVALID_IF(options.srcTransferFunctionParameters == nullptr,
"srcTransferFunctionParameters is nullptr when doing color conversion");
DAWN_INVALID_IF(options.conversionMatrix == nullptr,
"conversionMatrix is nullptr when doing color conversion");
DAWN_INVALID_IF(options.dstTransferFunctionParameters == nullptr,
"dstTransferFunctionParameters is nullptr when doing color conversion");
}
return {};
}
} // anonymous namespace
MaybeError ValidateCopyTextureForBrowser(DeviceBase* device,
const ImageCopyTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options) {
DAWN_TRY(device->ValidateObject(source->texture));
DAWN_INVALID_IF(source->texture->GetTextureState() == TextureBase::TextureState::Destroyed,
"Source texture %s is destroyed.", source->texture);
DAWN_TRY_CONTEXT(ValidateImageCopyTexture(device, *source, *copySize),
"validating the ImageCopyTexture for the source");
DAWN_TRY_CONTEXT(ValidateTextureCopyRange(device, *source, *copySize),
"validating that the copy fits in the source");
DAWN_TRY(ValidateTextureToTextureCopyCommonRestrictions(*source, *destination, *copySize));
DAWN_INVALID_IF(source->origin.z > 0, "Source has a non-zero z origin (%u).", source->origin.z);
DAWN_INVALID_IF(source->texture->GetSampleCount() > 1,
"The source texture sample count (%u) is not 1. ",
source->texture->GetSampleCount());
DAWN_INVALID_IF(
options->internalUsage && !device->HasFeature(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(ValidateCopyTextureSourceFormat(source->texture->GetFormat().format));
DAWN_TRY(ValidateCopyForBrowserCommonRestrictions(device, *destination, *copySize, *options));
return {};
}
MaybeError ValidateCopyExternalTextureForBrowser(DeviceBase* device,
const ImageCopyExternalTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options) {
DAWN_TRY(device->ValidateObject(source->externalTexture));
DAWN_TRY(source->externalTexture->ValidateCanUseInSubmitNow());
const Extent2D& sourceVisibleRect = source->externalTexture->GetVisibleRect();
// All texture dimensions are in uint32_t so by doing checks in uint64_t we avoid
// overflows.
DAWN_INVALID_IF(
static_cast<uint64_t>(source->origin.x) + static_cast<uint64_t>(copySize->width) >
static_cast<uint64_t>(sourceVisibleRect.width) ||
static_cast<uint64_t>(source->origin.y) + static_cast<uint64_t>(copySize->height) >
static_cast<uint64_t>(sourceVisibleRect.height) ||
static_cast<uint64_t>(source->origin.z) > 0,
"Texture copy range (origin: %s, copySize: %s) touches outside of %s visible size (%s).",
&source->origin, copySize, source->externalTexture, &sourceVisibleRect);
DAWN_INVALID_IF(source->origin.z > 0, "Source has a non-zero z origin (%u).", source->origin.z);
DAWN_INVALID_IF(
options->internalUsage && !device->HasFeature(Feature::DawnInternalUsages),
"The internalUsage is true while the dawn-internal-usages feature is not enabled.");
DAWN_TRY(ValidateCopyForBrowserCommonRestrictions(device, *destination, *copySize, *options));
return {};
}
MaybeError DoCopyExternalTextureForBrowser(DeviceBase* device,
const ImageCopyExternalTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options) {
TextureInfo info;
info.origin = source->origin;
const Extent2D& visibleRect = source->externalTexture->GetVisibleRect();
info.size = {visibleRect.width, visibleRect.height, 1};
RenderPipelineBase* pipeline;
DAWN_TRY_ASSIGN(pipeline, GetOrCreateCopyExternalTextureForBrowserPipeline(
device, destination->texture->GetFormat().format));
return DoCopyForBrowser<ExternalTextureBase>(device, &info, source->externalTexture,
destination, copySize, options, pipeline);
}
MaybeError DoCopyTextureForBrowser(DeviceBase* device,
const ImageCopyTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options) {
TextureInfo info;
info.origin = source->origin;
info.size = source->texture->GetSize();
Ref<TextureViewBase> srcTextureView = nullptr;
TextureViewDescriptor srcTextureViewDesc = {};
srcTextureViewDesc.dimension = wgpu::TextureViewDimension::e2D;
srcTextureViewDesc.baseMipLevel = source->mipLevel;
srcTextureViewDesc.mipLevelCount = 1;
srcTextureViewDesc.arrayLayerCount = 1;
DAWN_TRY_ASSIGN(srcTextureView,
device->CreateTextureView(source->texture, &srcTextureViewDesc));
RenderPipelineBase* pipeline;
DAWN_TRY_ASSIGN(pipeline, GetOrCreateCopyTextureForBrowserPipeline(
device, destination->texture->GetFormat().format));
return DoCopyForBrowser<TextureViewBase>(device, &info, srcTextureView.Get(), destination,
copySize, options, pipeline);
}
} // namespace dawn::native

View File

@ -30,12 +30,23 @@ MaybeError ValidateCopyTextureForBrowser(DeviceBase* device,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options);
MaybeError ValidateCopyExternalTextureForBrowser(DeviceBase* device,
const ImageCopyExternalTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options);
MaybeError DoCopyTextureForBrowser(DeviceBase* device,
const ImageCopyTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options);
MaybeError DoCopyExternalTextureForBrowser(DeviceBase* device,
const ImageCopyExternalTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options);
} // namespace dawn::native
#endif // SRC_DAWN_NATIVE_COPYTEXTUREFORBROWSERHELPER_H_

View File

@ -35,8 +35,10 @@ struct InternalPipelineStore {
~InternalPipelineStore();
std::unordered_map<wgpu::TextureFormat, Ref<RenderPipelineBase>> copyTextureForBrowserPipelines;
std::unordered_map<wgpu::TextureFormat, Ref<RenderPipelineBase>>
copyExternalTextureForBrowserPipelines;
Ref<ShaderModuleBase> copyTextureForBrowser;
Ref<ShaderModuleBase> copyForBrowser;
Ref<ComputePipelineBase> timestampComputePipeline;
Ref<ShaderModuleBase> timestampCS;

View File

@ -370,6 +370,14 @@ void QueueBase::APICopyTextureForBrowser(const ImageCopyTexture* source,
CopyTextureForBrowserInternal(source, destination, copySize, options));
}
void QueueBase::APICopyExternalTextureForBrowser(const ImageCopyExternalTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options) {
GetDevice()->ConsumedError(
CopyExternalTextureForBrowserInternal(source, destination, copySize, options));
}
MaybeError QueueBase::CopyTextureForBrowserInternal(const ImageCopyTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
@ -384,6 +392,21 @@ MaybeError QueueBase::CopyTextureForBrowserInternal(const ImageCopyTexture* sour
return DoCopyTextureForBrowser(GetDevice(), source, destination, copySize, options);
}
MaybeError QueueBase::CopyExternalTextureForBrowserInternal(
const ImageCopyExternalTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options) {
if (GetDevice()->IsValidationEnabled()) {
DAWN_TRY_CONTEXT(ValidateCopyExternalTextureForBrowser(GetDevice(), source, destination,
copySize, options),
"validating CopyExternalTextureForBrowser from %s to %s",
source->externalTexture, destination->texture);
}
return DoCopyExternalTextureForBrowser(GetDevice(), source, destination, copySize, options);
}
MaybeError QueueBase::ValidateSubmit(uint32_t commandCount,
CommandBufferBase* const* commands) const {
TRACE_EVENT0(GetDevice()->GetPlatform(), Validation, "Queue::ValidateSubmit");

View File

@ -58,6 +58,10 @@ class QueueBase : public ApiObjectBase {
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options);
void APICopyExternalTextureForBrowser(const ImageCopyExternalTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options);
MaybeError WriteBuffer(BufferBase* buffer,
uint64_t bufferOffset,
@ -82,6 +86,10 @@ class QueueBase : public ApiObjectBase {
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options);
MaybeError CopyExternalTextureForBrowserInternal(const ImageCopyExternalTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options);
virtual MaybeError SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) = 0;
virtual MaybeError WriteBufferImpl(BufferBase* buffer,

View File

@ -26,6 +26,7 @@
#include "dawn/native/BindGroupLayout.h"
#include "dawn/native/Buffer.h"
#include "dawn/native/Device.h"
#include "dawn/native/ExternalTexture.h"
#include "dawn/native/PipelineLayout.h"
#include "dawn/native/Queue.h"
#include "dawn/native/Sampler.h"
@ -140,6 +141,12 @@ BindingInitializationHelper::BindingInitializationHelper(uint32_t binding,
BindingInitializationHelper::BindingInitializationHelper(uint32_t binding,
const Ref<TextureViewBase>& textureView)
: binding(binding), textureView(textureView) {}
BindingInitializationHelper::BindingInitializationHelper(
uint32_t binding,
const Ref<ExternalTextureBase>& externalTexture)
: binding(binding), externalTexture(externalTexture) {
externalBindingEntry.externalTexture = externalTexture.Get();
}
BindingInitializationHelper::BindingInitializationHelper(uint32_t binding,
const Ref<BufferBase>& buffer,
@ -159,6 +166,10 @@ BindGroupEntry BindingInitializationHelper::GetAsBinding() const {
result.offset = offset;
result.size = size;
if (externalTexture != nullptr) {
result.nextInChain = &externalBindingEntry;
}
return result;
}

View File

@ -95,6 +95,7 @@ ResultOrError<Ref<BindGroupLayoutBase>> MakeBindGroupLayout(
struct BindingInitializationHelper {
BindingInitializationHelper(uint32_t binding, const Ref<SamplerBase>& sampler);
BindingInitializationHelper(uint32_t binding, const Ref<TextureViewBase>& textureView);
BindingInitializationHelper(uint32_t binding, const Ref<ExternalTextureBase>& externalTexture);
BindingInitializationHelper(uint32_t binding,
const Ref<BufferBase>& buffer,
uint64_t offset = 0,
@ -107,6 +108,8 @@ struct BindingInitializationHelper {
Ref<SamplerBase> sampler;
Ref<TextureViewBase> textureView;
Ref<BufferBase> buffer;
Ref<ExternalTextureBase> externalTexture;
ExternalTextureBindingEntry externalBindingEntry;
uint64_t offset = 0;
uint64_t size = 0;
};

View File

@ -45,6 +45,18 @@ AbslFormatConvert(const Color* value, const absl::FormatConversionSpec& spec, ab
return {true};
}
absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
const Extent2D* value,
const absl::FormatConversionSpec& spec,
absl::FormatSink* s) {
if (value == nullptr) {
s->Append("[null]");
return {true};
}
s->Append(absl::StrFormat("[Extent2D width:%u, height:%u]", value->width, value->height));
return {true};
}
absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
const Extent3D* value,
const absl::FormatConversionSpec& spec,

View File

@ -29,6 +29,12 @@ struct Color;
absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
AbslFormatConvert(const Color* value, const absl::FormatConversionSpec& spec, absl::FormatSink* s);
struct Extent2D;
absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
const Extent2D* value,
const absl::FormatConversionSpec& spec,
absl::FormatSink* s);
struct Extent3D;
absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
const Extent3D* value,

View File

@ -438,6 +438,7 @@ source_set("end2end_tests_sources") {
"end2end/ComputeLayoutMemoryBufferTests.cpp",
"end2end/ComputeSharedMemoryTests.cpp",
"end2end/ComputeStorageBufferBarrierTests.cpp",
"end2end/CopyExternalTextureForBrowserTests.cpp",
"end2end/CopyTests.cpp",
"end2end/CopyTextureForBrowserTests.cpp",
"end2end/CreatePipelineAsyncTests.cpp",

View File

@ -0,0 +1,207 @@
// 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.
#include <vector>
#include "dawn/tests/DawnTest.h"
#include "dawn/utils/ComboRenderPipelineDescriptor.h"
#include "dawn/utils/WGPUHelpers.h"
namespace {
wgpu::Texture Create2DTexture(wgpu::Device device,
uint32_t width,
uint32_t height,
wgpu::TextureFormat format,
wgpu::TextureUsage usage) {
wgpu::TextureDescriptor descriptor;
descriptor.dimension = wgpu::TextureDimension::e2D;
descriptor.size.width = width;
descriptor.size.height = height;
descriptor.size.depthOrArrayLayers = 1;
descriptor.sampleCount = 1;
descriptor.format = format;
descriptor.mipLevelCount = 1;
descriptor.usage = usage;
return device.CreateTexture(&descriptor);
}
static constexpr uint32_t kWidth = 4;
static constexpr uint32_t kHeight = 4;
std::array<std::array<utils::RGBA8, 4>, 4> kDefaultSourceRGBA = {
std::array<utils::RGBA8, 4>(
{utils::RGBA8::kBlack, utils::RGBA8::kBlack, utils::RGBA8::kRed, utils::RGBA8::kRed}),
std::array<utils::RGBA8, 4>(
{utils::RGBA8::kBlack, utils::RGBA8::kBlack, utils::RGBA8::kRed, utils::RGBA8::kRed}),
std::array<utils::RGBA8, 4>(
{utils::RGBA8::kGreen, utils::RGBA8::kGreen, utils::RGBA8::kBlue, utils::RGBA8::kBlue}),
std::array<utils::RGBA8, 4>(
{utils::RGBA8::kGreen, utils::RGBA8::kGreen, utils::RGBA8::kBlue, utils::RGBA8::kBlue})};
template <typename Parent>
class CopyExternalTextureForBrowserTests : public Parent {
protected:
wgpu::ExternalTexture CreateDefaultExternalTexture() {
// y plane
wgpu::TextureDescriptor externalTexturePlane0Desc = {};
externalTexturePlane0Desc.size = {kWidth, kHeight, 1};
externalTexturePlane0Desc.usage = wgpu::TextureUsage::TextureBinding |
wgpu::TextureUsage::CopyDst |
wgpu::TextureUsage::RenderAttachment;
externalTexturePlane0Desc.format = wgpu::TextureFormat::R8Unorm;
wgpu::Texture externalTexturePlane0 =
this->device.CreateTexture(&externalTexturePlane0Desc);
// The value Ref to ExternalTextureTest.cpp:
// {0.0, .5, .5, utils::RGBA8::kBlack, 0.0f},
// {0.2126, 0.4172, 1.0, utils::RGBA8::kRed, 1.0f},
// {0.7152, 0.1402, 0.0175, utils::RGBA8::kGreen, 0.0f},
// {0.0722, 1.0, 0.4937, utils::RGBA8::kBlue, 0.0f},
wgpu::ImageCopyTexture plane0 = {};
plane0.texture = externalTexturePlane0;
std::array<uint8_t, 16> yPlaneData = {0, 0, 54, 54, 0, 0, 54, 54,
182, 182, 18, 18, 182, 182, 18, 18};
wgpu::TextureDataLayout externalTexturePlane0DataLayout = {};
externalTexturePlane0DataLayout.bytesPerRow = 4;
this->queue.WriteTexture(&plane0, yPlaneData.data(), yPlaneData.size() * sizeof(float),
&externalTexturePlane0DataLayout, &externalTexturePlane0Desc.size);
// uv plane
wgpu::TextureDescriptor externalTexturePlane1Desc = {};
externalTexturePlane1Desc.size = {kWidth / 2, kHeight / 2, 1};
externalTexturePlane1Desc.usage = wgpu::TextureUsage::TextureBinding |
wgpu::TextureUsage::CopyDst |
wgpu::TextureUsage::RenderAttachment;
externalTexturePlane1Desc.format = wgpu::TextureFormat::RG8Unorm;
wgpu::Texture externalTexturePlane1 =
this->device.CreateTexture(&externalTexturePlane1Desc);
wgpu::ImageCopyTexture plane1 = {};
plane1.texture = externalTexturePlane1;
std::array<uint8_t, 8> uvPlaneData = {
128, 128, 106, 255, 36, 4, 255, 126,
};
wgpu::TextureDataLayout externalTexturePlane1DataLayout = {};
externalTexturePlane1DataLayout.bytesPerRow = 4;
this->queue.WriteTexture(&plane1, uvPlaneData.data(), uvPlaneData.size() * sizeof(float),
&externalTexturePlane1DataLayout, &externalTexturePlane1Desc.size);
// Create an ExternalTextureDescriptor from the texture views
wgpu::ExternalTextureDescriptor externalDesc;
utils::ColorSpaceConversionInfo info =
utils::GetYUVBT709ToRGBSRGBColorSpaceConversionInfo();
externalDesc.yuvToRgbConversionMatrix = info.yuvToRgbConversionMatrix.data();
externalDesc.gamutConversionMatrix = info.gamutConversionMatrix.data();
externalDesc.srcTransferFunctionParameters = info.srcTransferFunctionParameters.data();
externalDesc.dstTransferFunctionParameters = info.dstTransferFunctionParameters.data();
externalDesc.plane0 = externalTexturePlane0.CreateView();
externalDesc.plane1 = externalTexturePlane1.CreateView();
externalDesc.visibleRect = {kWidth, kHeight};
// Import the external texture
return this->device.CreateExternalTexture(&externalDesc);
}
std::vector<utils::RGBA8> GetDefaultExpectedData(bool flipY,
wgpu::Origin3D origin,
wgpu::Extent3D rect) {
std::vector<utils::RGBA8> expected;
for (uint32_t row = origin.y; row < origin.y + rect.height; ++row) {
for (uint32_t col = origin.x; col < origin.x + rect.width; ++col) {
if (flipY) {
uint32_t flippedRow = kHeight - row - 1;
expected.push_back(kDefaultSourceRGBA[flippedRow][col]);
} else {
expected.push_back(kDefaultSourceRGBA[row][col]);
}
}
}
return expected;
}
};
using FlipY = bool;
using SrcOrigin = wgpu::Origin3D;
using DstOrigin = wgpu::Origin3D;
std::ostream& operator<<(std::ostream& o, wgpu::Origin3D origin) {
o << origin.x << ", " << origin.y << ", " << origin.z;
return o;
}
DAWN_TEST_PARAM_STRUCT(CopyTestParams, SrcOrigin, DstOrigin, FlipY);
class CopyExternalTextureForBrowserTests_Basic
: public CopyExternalTextureForBrowserTests<DawnTestWithParams<CopyTestParams>> {
protected:
void DoBasicCopyTest(const wgpu::Origin3D& srcOrigin,
const wgpu::Origin3D& dstOrigin,
const wgpu::Extent3D& copySize,
const wgpu::CopyTextureForBrowserOptions options = {}) {
wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture();
wgpu::ImageCopyExternalTexture srcImageCopyExternalTexture;
srcImageCopyExternalTexture.externalTexture = externalTexture;
srcImageCopyExternalTexture.origin = srcOrigin;
wgpu::Texture dstTexture =
Create2DTexture(device, kWidth, kHeight, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
wgpu::TextureUsage::CopyDst);
wgpu::ImageCopyTexture dstImageCopyTexture =
utils::CreateImageCopyTexture(dstTexture, 0, dstOrigin);
queue.CopyExternalTextureForBrowser(&srcImageCopyExternalTexture, &dstImageCopyTexture,
&copySize, &options);
std::vector<utils::RGBA8> expected =
GetDefaultExpectedData(options.flipY, srcOrigin, copySize);
EXPECT_TEXTURE_EQ(expected.data(), dstTexture, dstOrigin, copySize);
}
};
} // anonymous namespace
TEST_P(CopyExternalTextureForBrowserTests_Basic, FullCopy) {
DAWN_SUPPRESS_TEST_IF(IsOpenGLES());
DAWN_SUPPRESS_TEST_IF(IsOpenGL() && IsLinux());
wgpu::CopyTextureForBrowserOptions options = {};
options.flipY = GetParam().mFlipY;
wgpu::Origin3D srcOrigin = GetParam().mSrcOrigin;
wgpu::Origin3D dstOrigin = GetParam().mDstOrigin;
wgpu::Extent3D copySize = {kWidth, kHeight};
if (srcOrigin.x != 0 || srcOrigin.y != 0 || dstOrigin.x != 0 || dstOrigin.y != 0) {
copySize.width = kWidth / 2;
copySize.height = kHeight / 2;
}
DoBasicCopyTest(srcOrigin, dstOrigin, copySize, options);
}
DAWN_INSTANTIATE_TEST_P(CopyExternalTextureForBrowserTests_Basic,
{D3D12Backend(), MetalBackend(), OpenGLBackend(), OpenGLESBackend(),
VulkanBackend()},
std::vector<wgpu::Origin3D>({{0, 0}, {2, 0}, {0, 2}, {2, 2}}),
std::vector<wgpu::Origin3D>({{0, 0}, {2, 0}, {0, 2}, {2, 2}}),
std::vector<bool>({false, true}));

View File

@ -39,10 +39,10 @@ class ExternalTextureTests : public DawnTest {
protected:
wgpu::ExternalTextureDescriptor CreateDefaultExternalTextureDescriptor() {
wgpu::ExternalTextureDescriptor desc;
desc.yuvToRgbConversionMatrix = kYuvToRGBMatrixBT709.data();
desc.gamutConversionMatrix = kGamutConversionMatrixBT709ToSrgb.data();
desc.srcTransferFunctionParameters = kGammaDecodeBT709.data();
desc.dstTransferFunctionParameters = kGammaEncodeSrgb.data();
desc.yuvToRgbConversionMatrix = yuvBT709ToRGBSRGB.yuvToRgbConversionMatrix.data();
desc.gamutConversionMatrix = yuvBT709ToRGBSRGB.gamutConversionMatrix.data();
desc.srcTransferFunctionParameters = yuvBT709ToRGBSRGB.srcTransferFunctionParameters.data();
desc.dstTransferFunctionParameters = yuvBT709ToRGBSRGB.dstTransferFunctionParameters.data();
return desc;
}
@ -51,14 +51,8 @@ class ExternalTextureTests : public DawnTest {
static constexpr uint32_t kHeight = 4;
static constexpr wgpu::TextureFormat kFormat = wgpu::TextureFormat::RGBA8Unorm;
static constexpr wgpu::TextureUsage kSampledUsage = wgpu::TextureUsage::TextureBinding;
std::array<float, 12> kYuvToRGBMatrixBT709 = {1.164384f, 0.0f, 1.792741f, -0.972945f,
1.164384f, -0.213249f, -0.532909f, 0.301483f,
1.164384f, 2.112402f, 0.0f, -1.133402f};
std::array<float, 9> kGamutConversionMatrixBT709ToSrgb = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f};
std::array<float, 7> kGammaDecodeBT709 = {2.2, 1.0 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081,
0.0, 0.0};
std::array<float, 7> kGammaEncodeSrgb = {1 / 2.4, 1.137119, 0.0, 12.92, 0.0031308, -0.055, 0.0};
utils::ColorSpaceConversionInfo yuvBT709ToRGBSRGB =
utils::GetYUVBT709ToRGBSRGBColorSpaceConversionInfo();
};
} // anonymous namespace
@ -99,7 +93,7 @@ TEST_P(ExternalTextureTests, SampleExternalTexture) {
@fragment fn main(@builtin(position) FragCoord : vec4<f32>)
-> @location(0) vec4<f32> {
return textureSampleLevel(t, s, FragCoord.xy / vec2<f32>(4.0, 4.0));
return textureSampleBaseClampToEdge(t, s, FragCoord.xy / vec2<f32>(4.0, 4.0));
})");
wgpu::Texture sampledTexture =
@ -184,7 +178,7 @@ TEST_P(ExternalTextureTests, SampleMultiplanarExternalTexture) {
@fragment fn main(@builtin(position) FragCoord : vec4<f32>)
-> @location(0) vec4<f32> {
return textureSampleLevel(t, s, FragCoord.xy / vec2<f32>(4.0, 4.0));
return textureSampleBaseClampToEdge(t, s, FragCoord.xy / vec2<f32>(4.0, 4.0));
})");
wgpu::Texture sampledTexturePlane0 =

View File

@ -20,31 +20,59 @@
#include "dawn/utils/TextureUtils.h"
#include "dawn/utils/WGPUHelpers.h"
namespace {
wgpu::Texture Create2DTexture(
wgpu::Device device,
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;
descriptor.size.depthOrArrayLayers = arrayLayerCount;
descriptor.sampleCount = sampleCount;
descriptor.format = format;
descriptor.mipLevelCount = mipLevelCount;
descriptor.usage = usage;
wgpu::Texture tex = device.CreateTexture(&descriptor);
return tex;
}
wgpu::ExternalTexture CreateExternalTexture(wgpu::Device device, uint32_t width, uint32_t height) {
wgpu::Texture texture =
Create2DTexture(device, width, height, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::TextureBinding);
// Create a texture view for the external texture
wgpu::TextureView view = texture.CreateView();
// Create an ExternalTextureDescriptor from the texture view
wgpu::ExternalTextureDescriptor externalDesc;
utils::ColorSpaceConversionInfo info = utils::GetYUVBT709ToRGBSRGBColorSpaceConversionInfo();
externalDesc.yuvToRgbConversionMatrix = info.yuvToRgbConversionMatrix.data();
externalDesc.gamutConversionMatrix = info.gamutConversionMatrix.data();
externalDesc.srcTransferFunctionParameters = info.srcTransferFunctionParameters.data();
externalDesc.dstTransferFunctionParameters = info.dstTransferFunctionParameters.data();
externalDesc.plane0 = view;
externalDesc.visibleRect = {width, height};
// Import the external texture
return device.CreateExternalTexture(&externalDesc);
}
} // namespace
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,
const wgpu::DawnTextureInternalUsageDescriptor* internalDesc = nullptr) {
wgpu::TextureDescriptor descriptor;
descriptor.nextInChain = internalDesc;
descriptor.dimension = wgpu::TextureDimension::e2D;
descriptor.size.width = width;
descriptor.size.height = height;
descriptor.size.depthOrArrayLayers = arrayLayerCount;
descriptor.sampleCount = sampleCount;
descriptor.format = format;
descriptor.mipLevelCount = mipLevelCount;
descriptor.usage = usage;
wgpu::Texture tex = device.CreateTexture(&descriptor);
return tex;
}
void TestCopyTextureForBrowser(utils::Expectation expectation,
wgpu::Texture srcTexture,
uint32_t srcLevel,
@ -81,13 +109,52 @@ class CopyTextureForBrowserInternalUsageTest : public CopyTextureForBrowserTest
}
};
class CopyExternalTextureForBrowserTest : public ValidationTest {
protected:
void TestCopyExternalTextureForBrowser(utils::Expectation expectation,
wgpu::ExternalTexture srcExternalTexture,
wgpu::Origin3D srcOrigin,
wgpu::Texture dstTexture,
uint32_t dstLevel,
wgpu::Origin3D dstOrigin,
wgpu::Extent3D extent3D,
wgpu::TextureAspect aspect = wgpu::TextureAspect::All,
wgpu::CopyTextureForBrowserOptions options = {}) {
wgpu::ImageCopyExternalTexture srcImageCopyExternalTexture;
srcImageCopyExternalTexture.externalTexture = srcExternalTexture;
srcImageCopyExternalTexture.origin = srcOrigin;
wgpu::ImageCopyTexture dstImageCopyTexture =
utils::CreateImageCopyTexture(dstTexture, dstLevel, dstOrigin, aspect);
if (expectation == utils::Expectation::Success) {
device.GetQueue().CopyExternalTextureForBrowser(
&srcImageCopyExternalTexture, &dstImageCopyTexture, &extent3D, &options);
} else {
ASSERT_DEVICE_ERROR(device.GetQueue().CopyExternalTextureForBrowser(
&srcImageCopyExternalTexture, &dstImageCopyTexture, &extent3D, &options));
}
}
};
class CopyExternalTextureForBrowserInternalUsageTest : public CopyExternalTextureForBrowserTest {
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 =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
// Different copies, including some that touch the OOB condition
@ -140,19 +207,20 @@ TEST_F(CopyTextureForBrowserTest, Success) {
// Test source or destination texture has wrong usages
TEST_F(CopyTextureForBrowserTest, IncorrectUsage) {
wgpu::Texture validSource =
Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture validDestination =
Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
wgpu::Texture noSampledUsageSource =
Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopySrc);
wgpu::Texture noRenderAttachmentUsageDestination =
Create2DTexture(16, 16, 5, 2, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst);
wgpu::Texture noSampledUsageSource = Create2DTexture(
device, 16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopySrc);
wgpu::Texture noRenderAttachmentUsageDestination = Create2DTexture(
device, 16, 16, 5, 2, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst);
wgpu::Texture noCopySrcUsageSource = Create2DTexture(
16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::TextureBinding);
wgpu::Texture noCopyDstUsageSource = Create2DTexture(
16, 16, 5, 2, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::RenderAttachment);
device, 16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::TextureBinding);
wgpu::Texture noCopyDstUsageSource =
Create2DTexture(device, 16, 16, 5, 2, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::RenderAttachment);
// Incorrect source usage causes failure : lack |Sampled| usage
TestCopyTextureForBrowser(utils::Expectation::Failure, noSampledUsageSource, 0, {0, 0, 0},
@ -178,10 +246,10 @@ TEST_F(CopyTextureForBrowserTest, DestroyedTexture) {
// Valid src and dst textures.
{
wgpu::Texture source =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All, options);
@ -194,10 +262,10 @@ TEST_F(CopyTextureForBrowserTest, DestroyedTexture) {
// Destroyed src texture.
{
wgpu::Texture source =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
source.Destroy();
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
@ -211,10 +279,10 @@ TEST_F(CopyTextureForBrowserTest, DestroyedTexture) {
// Destroyed dst texture.
{
wgpu::Texture source =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
destination.Destroy();
@ -230,10 +298,10 @@ TEST_F(CopyTextureForBrowserTest, DestroyedTexture) {
// Test non-zero value origin in source and OOB copy rects.
TEST_F(CopyTextureForBrowserTest, OutOfBounds) {
wgpu::Texture source =
Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
// OOB on source
@ -290,10 +358,10 @@ TEST_F(CopyTextureForBrowserTest, OutOfBounds) {
// Test destination texture has format that not supported by CopyTextureForBrowser().
TEST_F(CopyTextureForBrowserTest, InvalidDstFormat) {
wgpu::Texture source =
Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
Create2DTexture(16, 16, 5, 2, wgpu::TextureFormat::RG8Uint,
Create2DTexture(device, 16, 16, 5, 2, wgpu::TextureFormat::RG8Uint,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
// Not supported dst texture format.
@ -304,18 +372,18 @@ TEST_F(CopyTextureForBrowserTest, InvalidDstFormat) {
// Test source or destination texture are multisampled.
TEST_F(CopyTextureForBrowserTest, InvalidSampleCount) {
wgpu::Texture sourceMultiSampled1x =
Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding, 1);
wgpu::Texture destinationMultiSampled1x =
Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment, 1);
wgpu::Texture sourceMultiSampled4x =
Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding |
wgpu::TextureUsage::RenderAttachment,
4);
wgpu::Texture destinationMultiSampled4x =
Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment, 4);
// An empty copy with dst texture sample count > 1 failure.
@ -330,10 +398,10 @@ TEST_F(CopyTextureForBrowserTest, InvalidSampleCount) {
// Test color space conversion related attributes in CopyTextureForBrowserOptions.
TEST_F(CopyTextureForBrowserTest, ColorSpaceConversion_ColorSpace) {
wgpu::Texture source =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
wgpu::CopyTextureForBrowserOptions options = {};
@ -413,10 +481,10 @@ TEST_F(CopyTextureForBrowserTest, ColorSpaceConversion_ColorSpace) {
// Test option.srcAlphaMode/dstAlphaMode
TEST_F(CopyTextureForBrowserTest, ColorSpaceConversion_TextureAlphaState) {
wgpu::Texture source =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
wgpu::CopyTextureForBrowserOptions options = {};
@ -449,6 +517,342 @@ TEST_F(CopyTextureForBrowserTest, ColorSpaceConversion_TextureAlphaState) {
}
}
// Tests should be Success
TEST_F(CopyExternalTextureForBrowserTest, Success) {
wgpu::ExternalTexture source = CreateExternalTexture(device, 16, 16);
wgpu::Texture destination =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
// Different copies, including some that touch the OOB condition
{
// Copy a region along top left boundary
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1});
// Copy entire texture
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {16, 16, 1});
// Copy a region along bottom right boundary
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {8, 8, 0},
destination, 0, {8, 8, 0}, {8, 8, 1});
// Copy region into mip
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 2, {0, 0, 0}, {4, 4, 1});
// Copy between slices
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {0, 0, 1}, {16, 16, 1});
}
// Empty copies are valid
{
// An empty copy
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {0, 0, 1});
// An empty copy with depth = 0
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {0, 0, 0});
// An empty copy touching the side of the source texture
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {16, 16, 0}, {0, 0, 1});
// An empty copy touching the side of the destination texture
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {16, 16, 0}, {0, 0, 1});
}
}
// Test destination texture has wrong usages
TEST_F(CopyExternalTextureForBrowserTest, IncorrectUsage) {
wgpu::ExternalTexture validSource = CreateExternalTexture(device, 16, 16);
wgpu::Texture validDestination =
Create2DTexture(device, 16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
wgpu::Texture noRenderAttachmentUsageDestination = Create2DTexture(
device, 16, 16, 5, 2, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst);
wgpu::Texture noCopyDstUsageSource =
Create2DTexture(device, 16, 16, 5, 2, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::RenderAttachment);
// Incorrect destination usage causes failure: lack |RenderAttachement| usage.
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, validSource, {0, 0, 0},
noRenderAttachmentUsageDestination, 0, {0, 0, 0},
{16, 16, 1});
// Incorrect destination usage causes failure: lack |CopyDst| usage.
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, validSource, {0, 0, 0},
noCopyDstUsageSource, 0, {0, 0, 0}, {16, 16, 1});
}
// Test source or destination texture is destroyed.
TEST_F(CopyExternalTextureForBrowserTest, DestroyedTexture) {
wgpu::CopyTextureForBrowserOptions options = {};
// Valid src and dst textures.
{
wgpu::ExternalTexture source = CreateExternalTexture(device, 16, 16);
wgpu::Texture destination =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, options);
// Check noop copy
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {0, 0, 0},
wgpu::TextureAspect::All, options);
}
// Destroyed src texture.
{
wgpu::ExternalTexture source = CreateExternalTexture(device, 16, 16);
wgpu::Texture destination =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
source.Destroy();
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, options);
// Check noop copy
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {0, 0, 0},
wgpu::TextureAspect::All, options);
}
// Destroyed dst texture.
{
wgpu::ExternalTexture source = CreateExternalTexture(device, 16, 16);
wgpu::Texture destination =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
destination.Destroy();
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, options);
// Check noop copy
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {0, 0, 0},
wgpu::TextureAspect::All, options);
}
}
// Test non-zero value origin in source and OOB copy rects.
TEST_F(CopyExternalTextureForBrowserTest, OutOfBounds) {
wgpu::ExternalTexture source = CreateExternalTexture(device, 16, 16);
wgpu::Texture destination =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
// OOB on source
{
// x + width overflows
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {1, 0, 0},
destination, 0, {0, 0, 0}, {16, 16, 1});
// y + height overflows
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 1, 0},
destination, 0, {0, 0, 0}, {16, 16, 1});
// copy to multiple slices
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 0, 2}, {16, 16, 2});
// copy origin z value is non-zero.
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 1},
destination, 0, {0, 0, 2}, {16, 16, 1});
}
// OOB on destination
{
// x + width overflows
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {1, 0, 0}, {16, 16, 1});
// y + height overflows
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 1, 0}, {16, 16, 1});
// non-zero mip overflows
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 1, {0, 0, 0}, {9, 9, 1});
// arrayLayer + depth OOB
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 0, 4}, {16, 16, 1});
// empty copy on non-existent mip fails
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 6, {0, 0, 0}, {0, 0, 1});
// empty copy on non-existent slice fails
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 0, 4}, {0, 0, 1});
}
}
// Test destination texture has format that not supported by CopyTextureForBrowser().
TEST_F(CopyExternalTextureForBrowserTest, InvalidDstFormat) {
wgpu::ExternalTexture source = CreateExternalTexture(device, 16, 16);
wgpu::Texture destination =
Create2DTexture(device, 16, 16, 5, 2, wgpu::TextureFormat::RG8Uint,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
// Not supported dst texture format.
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, destination,
0, {0, 0, 0}, {0, 0, 1});
}
// Test destination texture are multisampled.
TEST_F(CopyExternalTextureForBrowserTest, InvalidSampleCount) {
wgpu::ExternalTexture source = CreateExternalTexture(device, 16, 16);
wgpu::Texture destinationMultiSampled4x =
Create2DTexture(device, 16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment, 4);
// An empty copy with dst texture sample count > 1 failure.
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destinationMultiSampled4x, 0, {0, 0, 0}, {0, 0, 1});
}
// Test color space conversion related attributes in CopyTextureForBrowserOptions.
TEST_F(CopyExternalTextureForBrowserTest, ColorSpaceConversion_ColorSpace) {
wgpu::ExternalTexture source = CreateExternalTexture(device, 16, 16);
wgpu::Texture destination =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
wgpu::CopyTextureForBrowserOptions options = {};
options.needsColorSpaceConversion = true;
// Valid cases
{
wgpu::CopyTextureForBrowserOptions validOptions = options;
std::array<float, 7> srcTransferFunctionParameters = {};
std::array<float, 7> dstTransferFunctionParameters = {};
std::array<float, 9> conversionMatrix = {};
validOptions.srcTransferFunctionParameters = srcTransferFunctionParameters.data();
validOptions.dstTransferFunctionParameters = dstTransferFunctionParameters.data();
validOptions.conversionMatrix = conversionMatrix.data();
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, validOptions);
// if no color space conversion, no need to validate related attributes
wgpu::CopyTextureForBrowserOptions noColorSpaceConversion = options;
noColorSpaceConversion.needsColorSpaceConversion = false;
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, noColorSpaceConversion);
}
// Invalid cases: srcTransferFunctionParameters, dstTransferFunctionParameters or
// conversionMatrix is nullptr or not set
{
// not set srcTransferFunctionParameters
wgpu::CopyTextureForBrowserOptions invalidOptions = options;
std::array<float, 7> dstTransferFunctionParameters = {};
std::array<float, 9> conversionMatrix = {};
invalidOptions.dstTransferFunctionParameters = dstTransferFunctionParameters.data();
invalidOptions.conversionMatrix = conversionMatrix.data();
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, invalidOptions);
// set to nullptr
invalidOptions.srcTransferFunctionParameters = nullptr;
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, invalidOptions);
}
{
// not set dstTransferFunctionParameters
wgpu::CopyTextureForBrowserOptions invalidOptions = options;
std::array<float, 7> srcTransferFunctionParameters = {};
std::array<float, 9> conversionMatrix = {};
invalidOptions.srcTransferFunctionParameters = srcTransferFunctionParameters.data();
invalidOptions.conversionMatrix = conversionMatrix.data();
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, invalidOptions);
// set to nullptr
invalidOptions.dstTransferFunctionParameters = nullptr;
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, invalidOptions);
}
{
// not set conversionMatrix
wgpu::CopyTextureForBrowserOptions invalidOptions = options;
std::array<float, 7> srcTransferFunctionParameters = {};
std::array<float, 7> dstTransferFunctionParameters = {};
invalidOptions.srcTransferFunctionParameters = srcTransferFunctionParameters.data();
invalidOptions.dstTransferFunctionParameters = dstTransferFunctionParameters.data();
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, invalidOptions);
// set to nullptr
invalidOptions.conversionMatrix = nullptr;
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, invalidOptions);
}
}
// Test option.srcAlphaMode/dstAlphaMode
TEST_F(CopyExternalTextureForBrowserTest, ColorSpaceConversion_TextureAlphaState) {
wgpu::ExternalTexture source = CreateExternalTexture(device, 16, 16);
wgpu::Texture destination =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
wgpu::CopyTextureForBrowserOptions options = {};
// Valid src texture alpha state and valid dst texture alpha state
{
options.srcAlphaMode = wgpu::AlphaMode::Premultiplied;
options.dstAlphaMode = wgpu::AlphaMode::Premultiplied;
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, options);
options.srcAlphaMode = wgpu::AlphaMode::Premultiplied;
options.dstAlphaMode = wgpu::AlphaMode::Unpremultiplied;
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, options);
options.srcAlphaMode = wgpu::AlphaMode::Unpremultiplied;
options.dstAlphaMode = wgpu::AlphaMode::Premultiplied;
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, options);
options.srcAlphaMode = wgpu::AlphaMode::Unpremultiplied;
options.dstAlphaMode = wgpu::AlphaMode::Unpremultiplied;
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
destination, 0, {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) {
@ -456,15 +860,15 @@ TEST_F(CopyTextureForBrowserTest, InternalUsage) {
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,
ASSERT_DEVICE_ERROR(Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc, 1, &internalDesc));
wgpu::Texture source =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
Create2DTexture(device, 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
@ -480,14 +884,15 @@ 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::Texture source = Create2DTexture(device, 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);
wgpu::Texture destination =
Create2DTexture(device, 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,
@ -499,3 +904,48 @@ TEST_F(CopyTextureForBrowserInternalUsageTest, InternalUsage) {
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {16, 16, 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(CopyExternalTextureForBrowserTest, 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(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc, 1, &internalDesc));
wgpu::ExternalTexture source = CreateExternalTexture(device, 16, 16);
wgpu::Texture destination =
Create2DTexture(device, 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;
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {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(CopyExternalTextureForBrowserInternalUsageTest, InternalUsage) {
wgpu::ExternalTexture source = CreateExternalTexture(device, 16, 16);
wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
internalDesc.internalUsage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment;
wgpu::Texture destination =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst, 1, &internalDesc);
// Without internal usage option should fail usage validation
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {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;
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, destination,
0, {0, 0, 0}, {16, 16, 1}, wgpu::TextureAspect::All, options);
}

View File

@ -26,6 +26,17 @@
#include "spirv-tools/optimizer.hpp"
namespace {
std::array<float, 12> kYuvToRGBMatrixBT709 = {1.164384f, 0.0f, 1.792741f, -0.972945f,
1.164384f, -0.213249f, -0.532909f, 0.301483f,
1.164384f, 2.112402f, 0.0f, -1.133402f};
std::array<float, 9> kGamutConversionMatrixBT709ToSrgb = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f};
std::array<float, 7> kGammaDecodeBT709 = {2.2, 1.0 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081,
0.0, 0.0};
std::array<float, 7> kGammaEncodeSrgb = {1 / 2.4, 1.137119, 0.0, 12.92, 0.0031308, -0.055, 0.0};
} // namespace
namespace utils {
wgpu::ShaderModule CreateShaderModuleFromASM(const wgpu::Device& device, const char* source) {
// Use SPIRV-Tools's C API to assemble the SPIR-V assembly text to binary. Because the types
@ -389,4 +400,14 @@ wgpu::BindGroup MakeBindGroup(
return device.CreateBindGroup(&descriptor);
}
ColorSpaceConversionInfo GetYUVBT709ToRGBSRGBColorSpaceConversionInfo() {
ColorSpaceConversionInfo info;
info.yuvToRgbConversionMatrix = kYuvToRGBMatrixBT709;
info.gamutConversionMatrix = kGamutConversionMatrixBT709ToSrgb;
info.srcTransferFunctionParameters = kGammaDecodeBT709;
info.dstTransferFunctionParameters = kGammaEncodeSrgb;
return info;
}
} // namespace utils

View File

@ -178,6 +178,15 @@ wgpu::BindGroup MakeBindGroup(
const wgpu::BindGroupLayout& layout,
std::initializer_list<BindingInitializationHelper> entriesInitializer);
struct ColorSpaceConversionInfo {
std::array<float, 12> yuvToRgbConversionMatrix;
std::array<float, 9> gamutConversionMatrix;
std::array<float, 7> srcTransferFunctionParameters;
std::array<float, 7> dstTransferFunctionParameters;
};
ColorSpaceConversionInfo GetYUVBT709ToRGBSRGBColorSpaceConversionInfo();
} // namespace utils
#endif // SRC_DAWN_UTILS_WGPUHELPERS_H_