blob: 9febeacfe2b74f27b137e7303c5fcca02f587641 [file] [log] [blame] [edit]
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <vector>
#include "dawn/tests/DawnTest.h"
#include "dawn/utils/ComboRenderPipelineDescriptor.h"
#include "dawn/utils/WGPUHelpers.h"
namespace dawn {
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> kDefaultExpectedRGBA = {
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})};
std::array<std::array<utils::RGBA8, 2>, 2> kDownScaledExpectedRGBA = {
std::array<utils::RGBA8, 2>({utils::RGBA8::kBlack, utils::RGBA8::kRed}),
std::array<utils::RGBA8, 2>({utils::RGBA8::kGreen, utils::RGBA8::kBlue})};
std::array<std::array<utils::RGBA8, 8>, 8> kUpScaledExpectedRGBA = {
std::array<utils::RGBA8, 8>({utils::RGBA8::kBlack, utils::RGBA8::kBlack, utils::RGBA8::kBlack,
utils::RGBA8::kBlack, utils::RGBA8::kRed, utils::RGBA8::kRed,
utils::RGBA8::kRed, utils::RGBA8::kRed}),
std::array<utils::RGBA8, 8>({utils::RGBA8::kBlack, utils::RGBA8::kBlack, utils::RGBA8::kBlack,
utils::RGBA8::kBlack, utils::RGBA8::kRed, utils::RGBA8::kRed,
utils::RGBA8::kRed, utils::RGBA8::kRed}),
std::array<utils::RGBA8, 8>({utils::RGBA8::kBlack, utils::RGBA8::kBlack, utils::RGBA8::kBlack,
utils::RGBA8::kBlack, utils::RGBA8::kRed, utils::RGBA8::kRed,
utils::RGBA8::kRed, utils::RGBA8::kRed}),
std::array<utils::RGBA8, 8>({utils::RGBA8::kBlack, utils::RGBA8::kBlack, utils::RGBA8::kBlack,
utils::RGBA8::kBlack, utils::RGBA8::kRed, utils::RGBA8::kRed,
utils::RGBA8::kRed, utils::RGBA8::kRed}),
std::array<utils::RGBA8, 8>({utils::RGBA8::kGreen, utils::RGBA8::kGreen, utils::RGBA8::kGreen,
utils::RGBA8::kGreen, utils::RGBA8::kBlue, utils::RGBA8::kBlue,
utils::RGBA8::kBlue, utils::RGBA8::kBlue}),
std::array<utils::RGBA8, 8>({utils::RGBA8::kGreen, utils::RGBA8::kGreen, utils::RGBA8::kGreen,
utils::RGBA8::kGreen, utils::RGBA8::kBlue, utils::RGBA8::kBlue,
utils::RGBA8::kBlue, utils::RGBA8::kBlue}),
std::array<utils::RGBA8, 8>({utils::RGBA8::kGreen, utils::RGBA8::kGreen, utils::RGBA8::kGreen,
utils::RGBA8::kGreen, utils::RGBA8::kBlue, utils::RGBA8::kBlue,
utils::RGBA8::kBlue, utils::RGBA8::kBlue}),
std::array<utils::RGBA8, 8>({utils::RGBA8::kGreen, utils::RGBA8::kGreen, utils::RGBA8::kGreen,
utils::RGBA8::kGreen, utils::RGBA8::kBlue, utils::RGBA8::kBlue,
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(yPlaneData[0]),
&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 = {};
// (Off-topic) spot-test for defaulting of .aspect.
plane1.aspect = wgpu::TextureAspect::Undefined;
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(uvPlaneData[0]),
&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.visibleOrigin = {0, 0};
externalDesc.visibleSize = {kWidth, kHeight};
// Import the external texture
return this->device.CreateExternalTexture(&externalDesc);
}
std::vector<utils::RGBA8> GetExpectedData(bool flipY,
wgpu::Origin3D srcOrigin,
wgpu::Extent3D rect,
wgpu::Extent2D naturalSize) {
std::vector<utils::RGBA8> expected;
for (uint32_t rowInRect = 0; rowInRect < rect.height; ++rowInRect) {
for (uint32_t colInRect = 0; colInRect < rect.width; ++colInRect) {
uint32_t row = rowInRect + srcOrigin.y;
uint32_t col = colInRect + srcOrigin.x;
if (flipY) {
row = (rect.height - rowInRect - 1) + srcOrigin.y;
}
// Upscale case
if (naturalSize.width > kWidth) {
expected.push_back(kUpScaledExpectedRGBA[row][col]);
} else if (naturalSize.width < kWidth) {
expected.push_back(kDownScaledExpectedRGBA[row][col]);
} else {
expected.push_back(kDefaultExpectedRGBA[row][col]);
}
}
}
return expected;
}
};
enum class CopyRect {
TopLeft,
TopRight,
BottomLeft,
BottomRight,
FullSize,
};
enum class ScaleType {
UpScale,
DownScale,
NoScale,
};
using FlipY = bool;
using CopySrcRect = CopyRect;
using CopyDstRect = CopyRect;
std::ostream& operator<<(std::ostream& o, ScaleType scaleType) {
switch (scaleType) {
case ScaleType::UpScale:
o << "UpScale";
break;
case ScaleType::DownScale:
o << "DownScale";
break;
case ScaleType::NoScale:
o << "DefaultSize";
break;
default:
DAWN_UNREACHABLE();
break;
}
return o;
}
std::ostream& operator<<(std::ostream& o, CopyRect copyRect) {
switch (copyRect) {
case CopyRect::TopLeft:
o << "TopLeftCopy";
break;
case CopyRect::TopRight:
o << "TopRightCopy";
break;
case CopyRect::BottomLeft:
o << "BottomLeftCopy";
break;
case CopyRect::BottomRight:
o << "BottomRightCopy";
break;
case CopyRect::FullSize:
o << "FullSizeCopy";
break;
default:
DAWN_UNREACHABLE();
break;
}
return o;
}
DAWN_TEST_PARAM_STRUCT(CopyTestParams, CopySrcRect, CopyDstRect, ScaleType, FlipY);
template <typename... Params>
class CopyExternalTextureForBrowserTestsBase
: public CopyExternalTextureForBrowserTests<DawnTestWithParams<Params...>> {
protected:
using DawnTestWithParams<Params...>::AddTextureExpectation;
void DoBasicCopyTest(const wgpu::Origin3D& srcOrigin,
const wgpu::Origin3D& dstOrigin,
const wgpu::Extent3D& copySize,
const wgpu::Extent2D& naturalSize,
const wgpu::Extent3D& dstTextureSize,
const wgpu::CopyTextureForBrowserOptions options = {},
const wgpu::TextureAspect dstAspect = wgpu::TextureAspect::All) {
wgpu::ExternalTexture externalTexture = this->CreateDefaultExternalTexture();
wgpu::ImageCopyExternalTexture srcImageCopyExternalTexture;
srcImageCopyExternalTexture.externalTexture = externalTexture;
srcImageCopyExternalTexture.origin = srcOrigin;
srcImageCopyExternalTexture.naturalSize = naturalSize;
wgpu::Texture dstTexture =
Create2DTexture(this->device, dstTextureSize.width, dstTextureSize.height,
wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
wgpu::TextureUsage::CopyDst);
wgpu::ImageCopyTexture dstImageCopyTexture =
utils::CreateImageCopyTexture(dstTexture, 0, dstOrigin, dstAspect);
this->queue.CopyExternalTextureForBrowser(&srcImageCopyExternalTexture,
&dstImageCopyTexture, &copySize, &options);
std::vector<utils::RGBA8> expected = this->GetExpectedData(
options.flipY, srcImageCopyExternalTexture.origin, copySize, naturalSize);
EXPECT_TEXTURE_EQ(expected.data(), dstTexture, dstOrigin, copySize);
}
};
class CopyExternalTextureForBrowserTests_Basic
: public CopyExternalTextureForBrowserTestsBase<CopyTestParams> {};
TEST_P(CopyExternalTextureForBrowserTests_Basic, Copy) {
DAWN_SUPPRESS_TEST_IF(IsOpenGLES());
DAWN_SUPPRESS_TEST_IF(IsOpenGL() && IsLinux());
wgpu::CopyTextureForBrowserOptions options = {};
options.flipY = GetParam().mFlipY;
CopyRect srcCopyRect = GetParam().mCopySrcRect;
CopyRect dstCopyRect = GetParam().mCopyDstRect;
ScaleType scaleType = GetParam().mScaleType;
// Test skip due to crbug.com/dawn/1719
DAWN_SUPPRESS_TEST_IF(IsWARP() && srcCopyRect != CopyRect::TopLeft &&
srcCopyRect != CopyRect::FullSize && dstCopyRect != CopyRect::TopLeft &&
dstCopyRect != CopyRect::FullSize && scaleType == ScaleType::DownScale);
float scaleFactor = 1.0;
switch (scaleType) {
case ScaleType::UpScale:
scaleFactor = 2.0;
break;
case ScaleType::DownScale:
scaleFactor = 0.5;
break;
case ScaleType::NoScale:
break;
default:
DAWN_UNREACHABLE();
break;
}
float defaultWidth = static_cast<float>(kWidth);
float defaultHeight = static_cast<float>(kHeight);
wgpu::Extent2D naturalSize = {static_cast<uint32_t>(defaultWidth * scaleFactor),
static_cast<uint32_t>(defaultHeight * scaleFactor)};
wgpu::Origin3D srcOrigin = {};
wgpu::Origin3D dstOrigin = {};
// Set copy size to sub rect copy size.
wgpu::Extent3D copySize = {naturalSize.width / 2, naturalSize.height / 2};
switch (srcCopyRect) {
// origin = {0, 0};
case CopyRect::TopLeft:
break;
case CopyRect::TopRight:
srcOrigin.x = naturalSize.width / 2;
srcOrigin.y = 0;
break;
case CopyRect::BottomLeft:
srcOrigin.x = 0;
srcOrigin.y = naturalSize.height / 2;
break;
case CopyRect::BottomRight:
srcOrigin.x = naturalSize.width / 2;
srcOrigin.y = naturalSize.height / 2;
break;
// origin = {0, 0}, copySize = naturalSize
case CopyRect::FullSize:
copySize.width = naturalSize.width;
copySize.height = naturalSize.height;
break;
default:
DAWN_UNREACHABLE();
break;
}
wgpu::Extent3D dstTextureSize = {copySize.width * 2, copySize.height * 2};
switch (dstCopyRect) {
case CopyRect::TopLeft:
break;
case CopyRect::TopRight:
dstOrigin.x = dstTextureSize.width / 2;
dstOrigin.y = 0;
break;
case CopyRect::BottomLeft:
dstOrigin.x = 0;
dstOrigin.y = dstTextureSize.height / 2;
break;
case CopyRect::BottomRight:
dstOrigin.x = dstTextureSize.width / 2;
dstOrigin.y = dstTextureSize.height / 2;
break;
case CopyRect::FullSize:
if (srcCopyRect != CopyRect::FullSize) {
dstTextureSize.width = copySize.width;
dstTextureSize.height = copySize.height;
}
break;
default:
DAWN_UNREACHABLE();
break;
}
DoBasicCopyTest(srcOrigin, dstOrigin, copySize, naturalSize, dstTextureSize, options);
}
DAWN_INSTANTIATE_TEST_P(
CopyExternalTextureForBrowserTests_Basic,
{D3D11Backend(), D3D12Backend(), MetalBackend(), OpenGLBackend(), OpenGLESBackend(),
VulkanBackend()},
std::vector<CopyRect>({CopyRect::TopLeft, CopyRect::TopRight, CopyRect::BottomLeft,
CopyRect::BottomRight, CopyRect::FullSize}),
std::vector<CopyRect>({CopyRect::TopLeft, CopyRect::TopRight, CopyRect::BottomLeft,
CopyRect::BottomRight, CopyRect::FullSize}),
std::vector<ScaleType>({ScaleType::UpScale, ScaleType::DownScale, ScaleType::NoScale}),
std::vector<FlipY>({false, true}));
// Spot-test for defaulting of .aspect
class CopyExternalTextureForBrowserTests_Aspect : public CopyExternalTextureForBrowserTestsBase<> {
};
TEST_P(CopyExternalTextureForBrowserTests_Aspect, Copy) {
DAWN_SUPPRESS_TEST_IF(IsOpenGLES());
DAWN_SUPPRESS_TEST_IF(IsOpenGL() && IsLinux());
wgpu::Origin3D srcOrigin = {};
wgpu::Origin3D dstOrigin = {};
wgpu::Extent2D naturalSize = {static_cast<uint32_t>(kWidth), static_cast<uint32_t>(kHeight)};
wgpu::Extent3D copySize = {naturalSize.width / 2, naturalSize.height / 2};
wgpu::Extent3D dstTextureSize = {copySize.width * 2, copySize.height * 2};
wgpu::CopyTextureForBrowserOptions options = {};
DoBasicCopyTest(srcOrigin, dstOrigin, copySize, naturalSize, dstTextureSize, options,
wgpu::TextureAspect::Undefined);
}
DAWN_INSTANTIATE_TEST(CopyExternalTextureForBrowserTests_Aspect,
D3D11Backend(),
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
OpenGLESBackend(),
VulkanBackend());
} // anonymous namespace
} // namespace dawn