VideoViewsTests: add test which uses a sampler per plane

This test sees flaky failures.
 - Check the entire checkerboard texture contents to get more
information.
 - Add a test which uses seperate sampling states to see if DX12
driver has difficulty sampling multi-planar formats using a
single sampler.
 - Also, double check support for the NV12 format in case
something in the driver flakily exposes support.

From https://dawn-review.googlesource.com/c/dawn/+/47660

Bug: dawn:733
Change-Id: I766907ff648f1dc35387902a70c3fb65debcaecd
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/119343
Commit-Queue: Austin Eng <enga@chromium.org>
Kokoro: Austin Eng <enga@chromium.org>
Reviewed-by: Shrek Shao <shrekshao@google.com>
This commit is contained in:
Austin Eng 2023-02-13 18:35:04 +00:00 committed by Dawn LUCI CQ
parent 44032e5084
commit 151913d29b
2 changed files with 135 additions and 52 deletions

View File

@ -71,45 +71,58 @@ std::vector<uint8_t> VideoViewsTests::GetTestTextureData(wgpu::TextureFormat for
constexpr uint8_t Yu = kYellowYUVColor[kYUVChromaPlaneIndex].r;
constexpr uint8_t Yv = kYellowYUVColor[kYUVChromaPlaneIndex].g;
constexpr uint8_t Wy = kWhiteYUVColor[kYUVLumaPlaneIndex].r;
constexpr uint8_t Wu = kWhiteYUVColor[kYUVChromaPlaneIndex].r;
constexpr uint8_t Wv = kWhiteYUVColor[kYUVChromaPlaneIndex].g;
constexpr uint8_t Ry = kRedYUVColor[kYUVLumaPlaneIndex].r;
constexpr uint8_t Ru = kRedYUVColor[kYUVChromaPlaneIndex].r;
constexpr uint8_t Rv = kRedYUVColor[kYUVChromaPlaneIndex].g;
constexpr uint8_t By = kBlueYUVColor[kYUVLumaPlaneIndex].r;
constexpr uint8_t Bu = kBlueYUVColor[kYUVChromaPlaneIndex].r;
constexpr uint8_t Bv = kBlueYUVColor[kYUVChromaPlaneIndex].g;
switch (format) {
// The first 16 bytes is the luma plane (Y), followed by the chroma plane (UV) which
// is half the number of bytes (subsampled by 2) but same bytes per line as luma
// plane.
case wgpu::TextureFormat::R8BG8Biplanar420Unorm:
if (isCheckerboard) {
constexpr uint8_t Wy = kWhiteYUVColor[kYUVLumaPlaneIndex].r;
constexpr uint8_t Wu = kWhiteYUVColor[kYUVChromaPlaneIndex].r;
constexpr uint8_t Wv = kWhiteYUVColor[kYUVChromaPlaneIndex].g;
constexpr uint8_t Ry = kRedYUVColor[kYUVLumaPlaneIndex].r;
constexpr uint8_t Ru = kRedYUVColor[kYUVChromaPlaneIndex].r;
constexpr uint8_t Rv = kRedYUVColor[kYUVChromaPlaneIndex].g;
constexpr uint8_t By = kBlueYUVColor[kYUVLumaPlaneIndex].r;
constexpr uint8_t Bu = kBlueYUVColor[kYUVChromaPlaneIndex].r;
constexpr uint8_t Bv = kBlueYUVColor[kYUVChromaPlaneIndex].g;
// clang-format off
return {
Wy, Wy, Ry, Ry, // plane 0, start + 0
Wy, Wy, Ry, Ry,
Yy, Yy, By, By,
Yy, Yy, By, By,
Wu, Wv, Ru, Rv, // plane 1, start + 16
Yu, Yv, Bu, Bv,
};
// clang-format on
return {
Wy, Wy, Ry, Ry, // plane 0, start + 0
Wy, Wy, Ry, Ry, //
Yy, Yy, By, By, //
Yy, Yy, By, By, //
Wu, Wv, Ru, Rv, // plane 1, start + 16
Yu, Yv, Bu, Bv, //
};
} else {
// clang-format off
return {
Yy, Yy, Yy, Yy, // plane 0, start + 0
Yy, Yy, Yy, Yy,
Yy, Yy, Yy, Yy,
Yy, Yy, Yy, Yy,
Yu, Yv, Yu, Yv, // plane 1, start + 16
Yu, Yv, Yu, Yv,
};
// clang-format on
return {
Yy, Yy, Yy, Yy, // plane 0, start + 0
Yy, Yy, Yy, Yy, //
Yy, Yy, Yy, Yy, //
Yy, Yy, Yy, Yy, //
Yu, Yv, Yu, Yv, // plane 1, start + 16
Yu, Yv, Yu, Yv, //
};
}
case wgpu::TextureFormat::RGBA8Unorm:
// Combines both NV12 planes by directly mapping back to RGB: R=Y, G=U, B=V.
if (isCheckerboard) {
return {
Yy, Yu, Yv, Yy, Yu, Yv, By, Bu, Bv, By, Bu, Bv, //
Yy, Yu, Yv, Yy, Yu, Yv, By, Bu, Bv, By, Bu, Bv, //
Wy, Wu, Wv, Wy, Wu, Wv, Ry, Ru, Rv, Ry, Ru, Rv, //
Wy, Wu, Wv, Wy, Wu, Wv, Ry, Ru, Rv, Ry, Ru, Rv, //
};
} else {
return {
Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, //
Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, //
Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, //
Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, //
};
}
default:
UNREACHABLE();
@ -323,8 +336,8 @@ TEST_P(VideoViewsTests, NV12SampleUVtoRG) {
mBackend->DestroyVideoTextureForTest(std::move(platformTexture));
}
// Renders a NV12 "checkerboard" texture into a RGB quad then checks the color at specific
// points to ensure the image has not been flipped.
// Renders a NV12 "checkerboard" texture into a RGB quad, then checks the the entire
// contents to ensure the image has not been flipped.
TEST_P(VideoViewsTests, NV12SampleYUVtoRGB) {
std::unique_ptr<VideoViewsTestBackend::PlatformTexture> platformTexture =
mBackend->CreateVideoTextureForTest(wgpu::TextureFormat::R8BG8Biplanar420Unorm,
@ -385,27 +398,90 @@ TEST_P(VideoViewsTests, NV12SampleYUVtoRGB) {
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
// Test four corners of the checkerboard image (YUV color space).
utils::RGBA8 yellowYUV(kYellowYUVColor[kYUVLumaPlaneIndex].r,
kYellowYUVColor[kYUVChromaPlaneIndex].r,
kYellowYUVColor[kYUVChromaPlaneIndex].g, 0xFF);
EXPECT_PIXEL_RGBA8_EQ(yellowYUV, renderPass.color, 0, 0); // top left
std::vector<uint8_t> expectedData = GetTestTextureData(wgpu::TextureFormat::RGBA8Unorm, true);
std::vector<utils::RGBA8> expectedRGBA;
for (uint8_t i = 0; i < expectedData.size(); i += 3) {
expectedRGBA.push_back({expectedData[i], expectedData[i + 1], expectedData[i + 2], 0xFF});
}
utils::RGBA8 redYUV(kRedYUVColor[kYUVLumaPlaneIndex].r, kRedYUVColor[kYUVChromaPlaneIndex].r,
kRedYUVColor[kYUVChromaPlaneIndex].g, 0xFF);
EXPECT_PIXEL_RGBA8_EQ(redYUV, renderPass.color, kYUVImageDataWidthInTexels - 1,
kYUVImageDataHeightInTexels - 1); // bottom right
EXPECT_TEXTURE_EQ(expectedRGBA.data(), renderPass.color, {0, 0},
{kYUVImageDataWidthInTexels, kYUVImageDataHeightInTexels});
mBackend->DestroyVideoTextureForTest(std::move(platformTexture));
}
utils::RGBA8 blueYUV(kBlueYUVColor[kYUVLumaPlaneIndex].r, kBlueYUVColor[kYUVChromaPlaneIndex].r,
kBlueYUVColor[kYUVChromaPlaneIndex].g, 0xFF);
EXPECT_PIXEL_RGBA8_EQ(blueYUV, renderPass.color, kYUVImageDataWidthInTexels - 1,
0); // top right
// Renders a NV12 "checkerboard" texture into a RGB quad with two samplers, then checks the the
// entire contents to ensure the image has not been flipped.
TEST_P(VideoViewsTests, NV12SampleYUVtoRGBMultipleSamplers) {
std::unique_ptr<VideoViewsTestBackend::PlatformTexture> platformTexture =
mBackend->CreateVideoTextureForTest(wgpu::TextureFormat::R8BG8Biplanar420Unorm,
wgpu::TextureUsage::TextureBinding,
/*isCheckerboard*/ true,
/*initialized*/ true);
ASSERT_NE(platformTexture.get(), nullptr);
if (!platformTexture->CanWrapAsWGPUTexture()) {
mBackend->DestroyVideoTextureForTest(std::move(platformTexture));
GTEST_SKIP() << "Skipped because not supported.";
}
utils::RGBA8 whiteYUV(kWhiteYUVColor[kYUVLumaPlaneIndex].r,
kWhiteYUVColor[kYUVChromaPlaneIndex].r,
kWhiteYUVColor[kYUVChromaPlaneIndex].g, 0xFF);
EXPECT_PIXEL_RGBA8_EQ(whiteYUV, renderPass.color, 0,
kYUVImageDataHeightInTexels - 1); // bottom left
wgpu::TextureViewDescriptor lumaViewDesc;
lumaViewDesc.format = wgpu::TextureFormat::R8Unorm;
lumaViewDesc.aspect = wgpu::TextureAspect::Plane0Only;
wgpu::TextureView lumaTextureView = platformTexture->wgpuTexture.CreateView(&lumaViewDesc);
wgpu::TextureViewDescriptor chromaViewDesc;
chromaViewDesc.format = wgpu::TextureFormat::RG8Unorm;
chromaViewDesc.aspect = wgpu::TextureAspect::Plane1Only;
wgpu::TextureView chromaTextureView = platformTexture->wgpuTexture.CreateView(&chromaViewDesc);
utils::ComboRenderPipelineDescriptor renderPipelineDescriptor;
renderPipelineDescriptor.vertex.module = GetTestVertexShaderModule();
renderPipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"(
@group(0) @binding(0) var sampler0 : sampler;
@group(0) @binding(1) var sampler1 : sampler;
@group(0) @binding(2) var lumaTexture : texture_2d<f32>;
@group(0) @binding(3) var chromaTexture : texture_2d<f32>;
@fragment
fn main(@location(0) texCoord : vec2f) -> @location(0) vec4f {
let y : f32 = textureSample(lumaTexture, sampler0, texCoord).r;
let u : f32 = textureSample(chromaTexture, sampler1, texCoord).r;
let v : f32 = textureSample(chromaTexture, sampler1, texCoord).g;
return vec4f(y, u, v, 1.0);
})");
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(
device, kYUVImageDataWidthInTexels, kYUVImageDataHeightInTexels);
renderPipelineDescriptor.cTargets[0].format = renderPass.colorFormat;
wgpu::RenderPipeline renderPipeline = device.CreateRenderPipeline(&renderPipelineDescriptor);
wgpu::Sampler sampler0 = device.CreateSampler();
wgpu::Sampler sampler1 = device.CreateSampler();
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
{
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
pass.SetPipeline(renderPipeline);
pass.SetBindGroup(
0, utils::MakeBindGroup(
device, renderPipeline.GetBindGroupLayout(0),
{{0, sampler0}, {1, sampler1}, {2, lumaTextureView}, {3, chromaTextureView}}));
pass.Draw(6);
pass.End();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
std::vector<uint8_t> expectedData = GetTestTextureData(wgpu::TextureFormat::RGBA8Unorm, true);
std::vector<utils::RGBA8> expectedRGBA;
for (uint8_t i = 0; i < expectedData.size(); i += 3) {
expectedRGBA.push_back({expectedData[i], expectedData[i + 1], expectedData[i + 2], 0xFF});
}
EXPECT_TEXTURE_EQ(expectedRGBA.data(), renderPass.color, {0, 0},
{kYUVImageDataWidthInTexels, kYUVImageDataHeightInTexels});
mBackend->DestroyVideoTextureForTest(std::move(platformTexture));
}

View File

@ -74,6 +74,13 @@ class VideoViewsTestBackendWin : public VideoViewsTestBackend {
ASSERT_GE(featureOptions5.SharedResourceTier, D3D11_SHARED_RESOURCE_TIER_2);
// Not all D3D11 devices support NV12 textures.
UINT formatSupport;
hr = d3d11Device->CheckFormatSupport(DXGI_FORMAT_NV12, &formatSupport);
ASSERT_EQ(hr, S_OK);
ASSERT_TRUE(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D);
mD3d11Device = std::move(d3d11Device);
}