blob: 9c7e1921c587e6ce69913aa14718ab32d22e46c3 [file] [log] [blame] [edit]
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/common/Assert.h"
#include "dawn/common/Constants.h"
#include "dawn/common/Math.h"
#include "dawn/tests/unittests/validation/ValidationTest.h"
#include "dawn/utils/TestUtils.h"
#include "dawn/utils/TextureUtils.h"
#include "dawn/utils/WGPUHelpers.h"
namespace dawn {
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.visibleOrigin = {0, 0};
externalDesc.visibleSize = {width, height};
// Import the external texture
return device.CreateExternalTexture(&externalDesc);
}
class CopyTextureForBrowserTest : public ValidationTest {
protected:
void TestCopyTextureForBrowser(utils::Expectation expectation,
wgpu::Texture srcTexture,
uint32_t srcLevel,
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::ImageCopyTexture srcImageCopyTexture =
utils::CreateImageCopyTexture(srcTexture, srcLevel, srcOrigin, aspect);
wgpu::ImageCopyTexture dstImageCopyTexture =
utils::CreateImageCopyTexture(dstTexture, dstLevel, dstOrigin, aspect);
if (expectation == utils::Expectation::Success) {
device.GetQueue().CopyTextureForBrowser(&srcImageCopyTexture, &dstImageCopyTexture,
&extent3D, &options);
} else {
ASSERT_DEVICE_ERROR(device.GetQueue().CopyTextureForBrowser(
&srcImageCopyTexture, &dstImageCopyTexture, &extent3D, &options));
}
}
};
class CopyTextureForBrowserInternalUsageTest : public CopyTextureForBrowserTest {
protected:
WGPUDevice CreateTestDevice(native::Adapter dawnAdapter,
wgpu::DeviceDescriptor descriptor) override {
wgpu::FeatureName feature = wgpu::FeatureName::DawnInternalUsages;
descriptor.requiredFeatures = &feature;
descriptor.requiredFeaturesCount = 1;
return dawnAdapter.CreateDevice(&descriptor);
}
};
class CopyExternalTextureForBrowserTest : public ValidationTest {
protected:
void TestCopyExternalTextureForBrowser(utils::Expectation expectation,
wgpu::ExternalTexture srcExternalTexture,
wgpu::Origin3D srcOrigin,
wgpu::Extent2D srcNaturalSize,
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;
srcImageCopyExternalTexture.naturalSize = srcNaturalSize;
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(native::Adapter dawnAdapter,
wgpu::DeviceDescriptor descriptor) override {
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(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
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
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {4, 4, 1});
// Copy entire texture
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {16, 16, 1});
// Copy a region along bottom right boundary
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {8, 8, 0}, destination, 0,
{8, 8, 0}, {8, 8, 1});
// Copy region into mip
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 2,
{0, 0, 0}, {4, 4, 1});
// Copy mip into region
TestCopyTextureForBrowser(utils::Expectation::Success, source, 2, {0, 0, 0}, destination, 0,
{0, 0, 0}, {4, 4, 1});
// Copy between slices
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 1}, {16, 16, 1});
}
// Empty copies are valid
{
// An empty copy
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {0, 0, 1});
// An empty copy with depth = 0
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {0, 0, 0});
// An empty copy touching the side of the source texture
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
{16, 16, 0}, {0, 0, 1});
// An empty copy touching the side of the destination texture
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
{16, 16, 0}, {0, 0, 1});
}
}
// Test source or destination texture has wrong usages
TEST_F(CopyTextureForBrowserTest, IncorrectUsage) {
wgpu::Texture validSource =
Create2DTexture(device, 16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture validDestination =
Create2DTexture(device, 16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
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(
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},
validDestination, 0, {0, 0, 0}, {16, 16, 1});
// Incorrect destination usage causes failure: lack |RenderAttachement| usage.
TestCopyTextureForBrowser(utils::Expectation::Failure, validSource, 0, {0, 0, 0},
noRenderAttachmentUsageDestination, 0, {0, 0, 0}, {16, 16, 1});
// Incorrect source usage causes failure : lack |CopySrc| usage
TestCopyTextureForBrowser(utils::Expectation::Failure, noCopySrcUsageSource, 0, {0, 0, 0},
validDestination, 0, {0, 0, 0}, {16, 16, 1});
// Incorrect destination usage causes failure: lack |CopyDst| usage.
TestCopyTextureForBrowser(utils::Expectation::Failure, validSource, 0, {0, 0, 0},
noCopyDstUsageSource, 0, {0, 0, 0}, {16, 16, 1});
}
// Test source or destination texture is destroyed.
TEST_F(CopyTextureForBrowserTest, DestroyedTexture) {
wgpu::CopyTextureForBrowserOptions options = {};
// Valid src and dst textures.
{
wgpu::Texture source =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
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);
// Check noop copy
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {0, 0, 0}, wgpu::TextureAspect::All, options);
}
// Destroyed src texture.
{
wgpu::Texture source =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
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,
{0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All, options);
// Check noop copy
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {0, 0, 0}, wgpu::TextureAspect::All, options);
}
// Destroyed dst texture.
{
wgpu::Texture source =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
destination.Destroy();
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All, options);
// Check noop copy
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {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(CopyTextureForBrowserTest, OutOfBounds) {
wgpu::Texture source =
Create2DTexture(device, 16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
// OOB on source
{
// x + width overflows
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {1, 0, 0}, destination, 0,
{0, 0, 0}, {16, 16, 1});
// y + height overflows
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 1, 0}, destination, 0,
{0, 0, 0}, {16, 16, 1});
// non-zero mip overflows
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0,
{0, 0, 0}, {9, 9, 1});
// copy to multiple slices
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 2}, {16, 16, 2});
// copy origin z value is non-zero.
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 1}, destination, 0,
{0, 0, 2}, {16, 16, 1});
}
// OOB on destination
{
// x + width overflows
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
{1, 0, 0}, {16, 16, 1});
// y + height overflows
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
{0, 1, 0}, {16, 16, 1});
// non-zero mip overflows
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 1,
{0, 0, 0}, {9, 9, 1});
// arrayLayer + depth OOB
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 4}, {16, 16, 1});
// empty copy on non-existent mip fails
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 6,
{0, 0, 0}, {0, 0, 1});
// empty copy on non-existent slice fails
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 4}, {0, 0, 1});
}
}
// Test destination texture has format that not supported by CopyTextureForBrowser().
TEST_F(CopyTextureForBrowserTest, InvalidDstFormat) {
wgpu::Texture source =
Create2DTexture(device, 16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
wgpu::Texture destination =
Create2DTexture(device, 16, 16, 5, 2, wgpu::TextureFormat::RG8Uint,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
// Not supported dst texture format.
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {0, 0, 1});
}
// Test source or destination texture are multisampled.
TEST_F(CopyTextureForBrowserTest, InvalidSampleCount) {
wgpu::Texture sourceMultiSampled1x =
Create2DTexture(device, 16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding, 1);
wgpu::Texture destinationMultiSampled1x =
Create2DTexture(device, 16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment, 1);
wgpu::Texture sourceMultiSampled4x =
Create2DTexture(device, 16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding |
wgpu::TextureUsage::RenderAttachment,
4);
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.
TestCopyTextureForBrowser(utils::Expectation::Failure, sourceMultiSampled1x, 0, {0, 0, 0},
destinationMultiSampled4x, 0, {0, 0, 0}, {0, 0, 1});
// A empty copy with source texture sample count > 1 failure
TestCopyTextureForBrowser(utils::Expectation::Failure, sourceMultiSampled4x, 0, {0, 0, 0},
destinationMultiSampled1x, 0, {0, 0, 0}, {0, 0, 1});
}
// Test color space conversion related attributes in CopyTextureForBrowserOptions.
TEST_F(CopyTextureForBrowserTest, ColorSpaceConversion_ColorSpace) {
wgpu::Texture source =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
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();
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {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;
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {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();
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All, invalidOptions);
// set to nullptr
invalidOptions.srcTransferFunctionParameters = nullptr;
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {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();
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All, invalidOptions);
// set to nullptr
invalidOptions.dstTransferFunctionParameters = nullptr;
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {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();
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All, invalidOptions);
// set to nullptr
invalidOptions.conversionMatrix = nullptr;
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All, invalidOptions);
}
}
// Test option.srcAlphaMode/dstAlphaMode
TEST_F(CopyTextureForBrowserTest, ColorSpaceConversion_TextureAlphaState) {
wgpu::Texture source =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
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;
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {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;
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {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;
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {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;
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All, options);
}
}
// 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}, {16, 16},
destination, 0, {0, 0, 0}, {4, 4, 1});
// Copy entire texture
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
destination, 0, {0, 0, 0}, {16, 16, 1});
// Copy a region along bottom right boundary
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {8, 8, 0}, {16, 16},
destination, 0, {8, 8, 0}, {8, 8, 1});
// Copy region into mip
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
destination, 2, {0, 0, 0}, {4, 4, 1});
// Copy between slices
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
destination, 0, {0, 0, 1}, {16, 16, 1});
}
// Empty copies are valid
{
// An empty copy
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
destination, 0, {0, 0, 0}, {0, 0, 1});
// An empty copy with depth = 0
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
noRenderAttachmentUsageDestination, 0, {0, 0, 0},
{16, 16, 1});
// Incorrect destination usage causes failure: lack |CopyDst| usage.
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, validSource, {0, 0, 0}, {16, 16},
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}, {16, 16},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, options);
// Check noop copy
TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
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}, {16, 16},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, options);
// Check noop copy
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
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}, {16, 16},
destination, 0, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::All, options);
// Check noop copy
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
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}, {4, 4},
destination, 0, {0, 0, 0}, {4, 4, 1});
// y + height overflows
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 1, 0}, {4, 4},
destination, 0, {0, 0, 0}, {4, 4, 1});
// copy to multiple slices
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {4, 4},
destination, 0, {0, 0, 2}, {4, 4, 2});
// copy origin z value is non-zero.
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 1}, {4, 4},
destination, 0, {0, 0, 2}, {4, 4, 1});
}
// OOB on destination
{
// x + width overflows
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
destination, 0, {1, 0, 0}, {16, 16, 1});
// y + height overflows
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
destination, 0, {0, 1, 0}, {16, 16, 1});
// non-zero mip overflows
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
destination, 1, {0, 0, 0}, {9, 9, 1});
// arrayLayer + depth OOB
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
destination, 0, {0, 0, 4}, {16, 16, 1});
// empty copy on non-existent mip fails
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
destination, 6, {0, 0, 0}, {0, 0, 1});
// empty copy on non-existent slice fails
TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
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) {
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::Texture source =
Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding);
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;
TestCopyTextureForBrowser(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {16, 16, 1}, wgpu::TextureAspect::All, options);
}
// Test that the internal usages are taken into account when interalUsage = true
TEST_F(CopyTextureForBrowserInternalUsageTest, InternalUsage) {
wgpu::DawnTextureInternalUsageDescriptor internalDesc1 = {};
internalDesc1.internalUsage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding;
wgpu::Texture source = Create2DTexture(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(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,
{0, 0, 0}, {16, 16, 1});
// With internal usage option should pass usage validation
wgpu::CopyTextureForBrowserOptions options = {};
options.internalUsage = true;
TestCopyTextureForBrowser(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
{0, 0, 0}, {16, 16, 1}, wgpu::TextureAspect::All, options);
}
// 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}, {16, 16},
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}, {16, 16},
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}, {16, 16},
destination, 0, {0, 0, 0}, {16, 16, 1},
wgpu::TextureAspect::All, options);
}
} // anonymous namespace
} // namespace dawn