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:
parent
44032e5084
commit
151913d29b
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue