blob: a16eb092aa5f49963644351da2f551d8a9940497 [file] [log] [blame]
// Copyright 2021 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 "src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.h"
#include "src/tint/lang/wgsl/ast/transform/helper_test.h"
namespace tint::ast::transform {
namespace {
using MultiplanarExternalTextureTest = TransformTest;
TEST_F(MultiplanarExternalTextureTest, ShouldRunEmptyModule) {
auto* src = R"()";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
EXPECT_FALSE(ShouldRun<MultiplanarExternalTexture>(src, data));
}
TEST_F(MultiplanarExternalTextureTest, ShouldRunHasExternalTextureAlias) {
auto* src = R"(
alias ET = texture_external;
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
EXPECT_TRUE(ShouldRun<MultiplanarExternalTexture>(src, data));
}
TEST_F(MultiplanarExternalTextureTest, ShouldRunHasExternalTextureGlobal) {
auto* src = R"(
@group(0) @binding(0) var ext_tex : texture_external;
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
EXPECT_TRUE(ShouldRun<MultiplanarExternalTexture>(src, data));
}
TEST_F(MultiplanarExternalTextureTest, ShouldRunHasExternalTextureParam) {
auto* src = R"(
fn f(ext_tex : texture_external) {}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
EXPECT_TRUE(ShouldRun<MultiplanarExternalTexture>(src, data));
}
// Running the transform without passing in data for the new bindings should result in an error.
TEST_F(MultiplanarExternalTextureTest, ErrorNoPassedData_SampleBaseClampToEdge) {
auto* src = R"(
@group(0) @binding(0) var s : sampler;
@group(0) @binding(1) var ext_tex : texture_external;
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
return textureSampleBaseClampToEdge(ext_tex, s, coord.xy);
}
)";
auto* expect =
"error: missing new binding point data for "
"tint::ast::transform::MultiplanarExternalTexture";
auto got = Run<MultiplanarExternalTexture>(src);
EXPECT_EQ(expect, str(got));
}
// Running the transform with incorrect binding data should result in an error.
TEST_F(MultiplanarExternalTextureTest, ErrorIncorrectBindingPont_SampleBaseClampToEdge) {
auto* src = R"(
@group(0) @binding(0) var s : sampler;
@group(0) @binding(1) var ext_tex : texture_external;
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
return textureSampleBaseClampToEdge(ext_tex, s, coord.xy);
}
)";
auto* expect = R"(error: missing new binding points for texture_external at binding {0,1})";
DataMap data;
// This bindings map specifies 0,0 as the location of the texture_external,
// which is incorrect.
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the transform works with a textureDimensions call.
TEST_F(MultiplanarExternalTextureTest, Dimensions) {
auto* src = R"(
@group(0) @binding(0) var ext_tex : texture_external;
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
var dim : vec2<u32>;
dim = textureDimensions(ext_tex);
return vec4<f32>(0.0, 0.0, 0.0, 0.0);
}
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(2) var<uniform> ext_tex_params : ExternalTextureParams;
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
var dim : vec2<u32>;
dim = (ext_tex_params.visibleSize + vec2<u32>(1));
return vec4<f32>(0.0, 0.0, 0.0, 0.0);
}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
TEST_F(MultiplanarExternalTextureTest, Collisions) {
auto* src = R"(
@group(0) @binding(0) var myTexture: texture_external;
@fragment
fn fragmentMain() -> @location(0) vec4f {
let result = textureLoad(myTexture, vec2u(1, 1));
return vec4f(1);
})";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@internal(disable_validation__binding_point_collision) @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@internal(disable_validation__binding_point_collision) @group(0) @binding(0) var<uniform> ext_tex_params : ExternalTextureParams;
@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var myTexture : texture_2d<f32>;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<u32>, params : ExternalTextureParams) -> vec4<f32> {
let clampedCoords = min(vec2<u32>(coord), params.visibleSize);
let plane0_clamped = vec2<u32>(round((params.loadTransform * vec3<f32>(vec2<f32>(clampedCoords), 1))));
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureLoad(plane0, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = vec2<u32>((vec2<f32>(plane0_clamped) * params.plane1CoordFactor));
color = vec4<f32>((vec4<f32>(textureLoad(plane0, plane0_clamped, 0).r, textureLoad(plane1, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
@fragment
fn fragmentMain() -> @location(0) vec4f {
let result = textureLoadExternal(myTexture, ext_tex_plane_1, vec2u(1, 1), ext_tex_params);
return vec4f(1);
}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 0}}}},
/* allow collisions */ true);
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the transform works with a textureDimensions call.
TEST_F(MultiplanarExternalTextureTest, Dimensions_OutOfOrder) {
auto* src = R"(
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
var dim : vec2<u32>;
dim = textureDimensions(ext_tex);
return vec4<f32>(0.0, 0.0, 0.0, 0.0);
}
@group(0) @binding(0) var ext_tex : texture_external;
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(2) var<uniform> ext_tex_params : ExternalTextureParams;
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
var dim : vec2<u32>;
dim = (ext_tex_params.visibleSize + vec2<u32>(1));
return vec4<f32>(0.0, 0.0, 0.0, 0.0);
}
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Test that the transform works with a textureSampleBaseClampToEdge call.
TEST_F(MultiplanarExternalTextureTest, BasicTextureSampleBaseClampToEdge) {
auto* src = R"(
@group(0) @binding(0) var s : sampler;
@group(0) @binding(1) var ext_tex : texture_external;
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
return textureSampleBaseClampToEdge(ext_tex, s, coord.xy);
}
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
@group(0) @binding(0) var s : sampler;
@group(0) @binding(1) var ext_tex : texture_2d<f32>;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
return textureSampleExternal(ext_tex, ext_tex_plane_1, s, coord.xy, ext_tex_params);
}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Test that the transform works with a textureSampleBaseClampToEdge call.
TEST_F(MultiplanarExternalTextureTest, BasicTextureSampleBaseClampToEdge_OutOfOrder) {
auto* src = R"(
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
return textureSampleBaseClampToEdge(ext_tex, s, coord.xy);
}
@group(0) @binding(1) var ext_tex : texture_external;
@group(0) @binding(0) var s : sampler;
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
return textureSampleExternal(ext_tex, ext_tex_plane_1, s, coord.xy, ext_tex_params);
}
@group(0) @binding(1) var ext_tex : texture_2d<f32>;
@group(0) @binding(0) var s : sampler;
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the transform works with a textureLoad call.
TEST_F(MultiplanarExternalTextureTest, BasicTextureLoad) {
auto* src = R"(
@group(0) @binding(0) var ext_tex : texture_external;
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
var val_signed = textureLoad(ext_tex, vec2<i32>(1));
var val_unsigned = textureLoad(ext_tex, vec2<u32>(1));
return val_signed + val_unsigned;
}
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(2) var<uniform> ext_tex_params : ExternalTextureParams;
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
let clampedCoords = min(vec2<u32>(coord), params.visibleSize);
let plane0_clamped = vec2<u32>(round((params.loadTransform * vec3<f32>(vec2<f32>(clampedCoords), 1))));
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureLoad(plane0, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = vec2<u32>((vec2<f32>(plane0_clamped) * params.plane1CoordFactor));
color = vec4<f32>((vec4<f32>(textureLoad(plane0, plane0_clamped, 0).r, textureLoad(plane1, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
fn textureLoadExternal_1(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<u32>, params : ExternalTextureParams) -> vec4<f32> {
let clampedCoords = min(vec2<u32>(coord), params.visibleSize);
let plane0_clamped = vec2<u32>(round((params.loadTransform * vec3<f32>(vec2<f32>(clampedCoords), 1))));
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureLoad(plane0, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = vec2<u32>((vec2<f32>(plane0_clamped) * params.plane1CoordFactor));
color = vec4<f32>((vec4<f32>(textureLoad(plane0, plane0_clamped, 0).r, textureLoad(plane1, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
var val_signed = textureLoadExternal(ext_tex, ext_tex_plane_1, vec2<i32>(1), ext_tex_params);
var val_unsigned = textureLoadExternal_1(ext_tex, ext_tex_plane_1, vec2<u32>(1), ext_tex_params);
return (val_signed + val_unsigned);
}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the transform works with a textureLoad call.
TEST_F(MultiplanarExternalTextureTest, BasicTextureLoad_OutOfOrder) {
auto* src = R"(
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
var val_signed = textureLoad(ext_tex, vec2<i32>(1));
var val_unsigned = textureLoad(ext_tex, vec2<u32>(1));
return val_signed + val_unsigned;
}
@group(0) @binding(0) var ext_tex : texture_external;
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(2) var<uniform> ext_tex_params : ExternalTextureParams;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
let clampedCoords = min(vec2<u32>(coord), params.visibleSize);
let plane0_clamped = vec2<u32>(round((params.loadTransform * vec3<f32>(vec2<f32>(clampedCoords), 1))));
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureLoad(plane0, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = vec2<u32>((vec2<f32>(plane0_clamped) * params.plane1CoordFactor));
color = vec4<f32>((vec4<f32>(textureLoad(plane0, plane0_clamped, 0).r, textureLoad(plane1, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
fn textureLoadExternal_1(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<u32>, params : ExternalTextureParams) -> vec4<f32> {
let clampedCoords = min(vec2<u32>(coord), params.visibleSize);
let plane0_clamped = vec2<u32>(round((params.loadTransform * vec3<f32>(vec2<f32>(clampedCoords), 1))));
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureLoad(plane0, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = vec2<u32>((vec2<f32>(plane0_clamped) * params.plane1CoordFactor));
color = vec4<f32>((vec4<f32>(textureLoad(plane0, plane0_clamped, 0).r, textureLoad(plane1, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
var val_signed = textureLoadExternal(ext_tex, ext_tex_plane_1, vec2<i32>(1), ext_tex_params);
var val_unsigned = textureLoadExternal_1(ext_tex, ext_tex_plane_1, vec2<u32>(1), ext_tex_params);
return (val_signed + val_unsigned);
}
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the transform works with both a textureSampleBaseClampToEdge and textureLoad call.
TEST_F(MultiplanarExternalTextureTest, TextureSampleBaseClampToEdgeAndTextureLoad) {
auto* src = R"(
@group(0) @binding(0) var s : sampler;
@group(0) @binding(1) var ext_tex : texture_external;
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
return textureSampleBaseClampToEdge(ext_tex, s, coord.xy) + textureLoad(ext_tex, vec2<i32>(1, 1));
}
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
@group(0) @binding(0) var s : sampler;
@group(0) @binding(1) var ext_tex : texture_2d<f32>;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
let clampedCoords = min(vec2<u32>(coord), params.visibleSize);
let plane0_clamped = vec2<u32>(round((params.loadTransform * vec3<f32>(vec2<f32>(clampedCoords), 1))));
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureLoad(plane0, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = vec2<u32>((vec2<f32>(plane0_clamped) * params.plane1CoordFactor));
color = vec4<f32>((vec4<f32>(textureLoad(plane0, plane0_clamped, 0).r, textureLoad(plane1, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
return (textureSampleExternal(ext_tex, ext_tex_plane_1, s, coord.xy, ext_tex_params) + textureLoadExternal(ext_tex, ext_tex_plane_1, vec2<i32>(1, 1), ext_tex_params));
}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the transform works with both a textureSampleBaseClampToEdge and textureLoad call.
TEST_F(MultiplanarExternalTextureTest, TextureSampleBaseClampToEdgeAndTextureLoad_OutOfOrder) {
auto* src = R"(
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
return textureSampleBaseClampToEdge(ext_tex, s, coord.xy) + textureLoad(ext_tex, vec2<i32>(1, 1));
}
@group(0) @binding(0) var s : sampler;
@group(0) @binding(1) var ext_tex : texture_external;
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
let clampedCoords = min(vec2<u32>(coord), params.visibleSize);
let plane0_clamped = vec2<u32>(round((params.loadTransform * vec3<f32>(vec2<f32>(clampedCoords), 1))));
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureLoad(plane0, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = vec2<u32>((vec2<f32>(plane0_clamped) * params.plane1CoordFactor));
color = vec4<f32>((vec4<f32>(textureLoad(plane0, plane0_clamped, 0).r, textureLoad(plane1, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
return (textureSampleExternal(ext_tex, ext_tex_plane_1, s, coord.xy, ext_tex_params) + textureLoadExternal(ext_tex, ext_tex_plane_1, vec2<i32>(1, 1), ext_tex_params));
}
@group(0) @binding(0) var s : sampler;
@group(0) @binding(1) var ext_tex : texture_2d<f32>;
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the transform works with many instances of texture_external.
TEST_F(MultiplanarExternalTextureTest, ManyTextureSampleBaseClampToEdge) {
auto* src = R"(
@group(0) @binding(0) var s : sampler;
@group(0) @binding(1) var ext_tex : texture_external;
@group(0) @binding(2) var ext_tex_1 : texture_external;
@group(0) @binding(3) var ext_tex_2 : texture_external;
@group(1) @binding(0) var ext_tex_3 : texture_external;
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
return textureSampleBaseClampToEdge(ext_tex, s, coord.xy) +
textureSampleBaseClampToEdge(ext_tex_1, s, coord.xy) +
textureSampleBaseClampToEdge(ext_tex_2, s, coord.xy) +
textureSampleBaseClampToEdge(ext_tex_3, s, coord.xy);
}
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(4) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(5) var<uniform> ext_tex_params : ExternalTextureParams;
@group(0) @binding(6) var ext_tex_plane_1_1 : texture_2d<f32>;
@group(0) @binding(7) var<uniform> ext_tex_params_1 : ExternalTextureParams;
@group(0) @binding(8) var ext_tex_plane_1_2 : texture_2d<f32>;
@group(0) @binding(9) var<uniform> ext_tex_params_2 : ExternalTextureParams;
@group(1) @binding(1) var ext_tex_plane_1_3 : texture_2d<f32>;
@group(1) @binding(2) var<uniform> ext_tex_params_3 : ExternalTextureParams;
@group(0) @binding(0) var s : sampler;
@group(0) @binding(1) var ext_tex : texture_2d<f32>;
@group(0) @binding(2) var ext_tex_1 : texture_2d<f32>;
@group(0) @binding(3) var ext_tex_2 : texture_2d<f32>;
@group(1) @binding(0) var ext_tex_3 : texture_2d<f32>;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
return (((textureSampleExternal(ext_tex, ext_tex_plane_1, s, coord.xy, ext_tex_params) + textureSampleExternal(ext_tex_1, ext_tex_plane_1_1, s, coord.xy, ext_tex_params_1)) + textureSampleExternal(ext_tex_2, ext_tex_plane_1_2, s, coord.xy, ext_tex_params_2)) + textureSampleExternal(ext_tex_3, ext_tex_plane_1_3, s, coord.xy, ext_tex_params_3));
}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
{{0, 1}, {{0, 4}, {0, 5}}},
{{0, 2}, {{0, 6}, {0, 7}}},
{{0, 3}, {{0, 8}, {0, 9}}},
{{1, 0}, {{1, 1}, {1, 2}}},
});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the texture_external passed as a function parameter produces the
// correct output.
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParam) {
auto* src = R"(
fn f(t : texture_external, s : sampler) {
_ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
@group(0) @binding(0) var ext_tex : texture_external;
@group(0) @binding(1) var smp : sampler;
@fragment
fn main() {
f(ext_tex, smp);
}
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
_ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
}
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
@group(0) @binding(1) var smp : sampler;
@fragment
fn main() {
f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
{{0, 0}, {{0, 2}, {0, 3}}},
});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the texture_external passed as a function parameter produces the
// correct output.
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParam_OutOfOrder) {
auto* src = R"(
@fragment
fn main() {
f(ext_tex, smp);
}
fn f(t : texture_external, s : sampler) {
_ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
@group(0) @binding(0) var ext_tex : texture_external;
@group(0) @binding(1) var smp : sampler;
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
@fragment
fn main() {
f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
}
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
_ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
}
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
@group(0) @binding(1) var smp : sampler;
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
{{0, 0}, {{0, 2}, {0, 3}}},
});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the texture_external passed as a parameter not in the first
// position produces the correct output.
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsSecondParam) {
auto* src = R"(
fn f(s : sampler, t : texture_external) {
_ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
@group(0) @binding(0) var ext_tex : texture_external;
@group(0) @binding(1) var smp : sampler;
@fragment
fn main() {
f(smp, ext_tex);
}
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
fn f(s : sampler, t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams) {
_ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
}
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
@group(0) @binding(1) var smp : sampler;
@fragment
fn main() {
f(smp, ext_tex, ext_tex_plane_1, ext_tex_params);
}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
{{0, 0}, {{0, 2}, {0, 3}}},
});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that multiple texture_external params passed to a function produces the
// correct output.
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamMultiple) {
auto* src = R"(
fn f(t : texture_external, s : sampler, t2 : texture_external) {
_ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
_ = textureSampleBaseClampToEdge(t2, s, vec2<f32>(1.0, 2.0));
}
@group(0) @binding(0) var ext_tex : texture_external;
@group(0) @binding(1) var smp : sampler;
@group(0) @binding(2) var ext_tex2 : texture_external;
@fragment
fn main() {
f(ext_tex, smp, ext_tex2);
}
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(3) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(4) var<uniform> ext_tex_params : ExternalTextureParams;
@group(0) @binding(5) var ext_tex_plane_1_1 : texture_2d<f32>;
@group(0) @binding(6) var<uniform> ext_tex_params_1 : ExternalTextureParams;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler, t2 : texture_2d<f32>, ext_tex_plane_1_3 : texture_2d<f32>, ext_tex_params_3 : ExternalTextureParams) {
_ = textureSampleExternal(t, ext_tex_plane_1_2, s, vec2<f32>(1.0, 2.0), ext_tex_params_2);
_ = textureSampleExternal(t2, ext_tex_plane_1_3, s, vec2<f32>(1.0, 2.0), ext_tex_params_3);
}
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
@group(0) @binding(1) var smp : sampler;
@group(0) @binding(2) var ext_tex2 : texture_2d<f32>;
@fragment
fn main() {
f(ext_tex, ext_tex_plane_1, ext_tex_params, smp, ext_tex2, ext_tex_plane_1_1, ext_tex_params_1);
}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
{{0, 0}, {{0, 3}, {0, 4}}},
{{0, 2}, {{0, 5}, {0, 6}}},
});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that multiple texture_external params passed to a function produces the
// correct output.
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamMultiple_OutOfOrder) {
auto* src = R"(
@fragment
fn main() {
f(ext_tex, smp, ext_tex2);
}
fn f(t : texture_external, s : sampler, t2 : texture_external) {
_ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
_ = textureSampleBaseClampToEdge(t2, s, vec2<f32>(1.0, 2.0));
}
@group(0) @binding(0) var ext_tex : texture_external;
@group(0) @binding(1) var smp : sampler;
@group(0) @binding(2) var ext_tex2 : texture_external;
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(3) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(4) var<uniform> ext_tex_params : ExternalTextureParams;
@group(0) @binding(5) var ext_tex_plane_1_1 : texture_2d<f32>;
@group(0) @binding(6) var<uniform> ext_tex_params_1 : ExternalTextureParams;
@fragment
fn main() {
f(ext_tex, ext_tex_plane_1, ext_tex_params, smp, ext_tex2, ext_tex_plane_1_1, ext_tex_params_1);
}
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler, t2 : texture_2d<f32>, ext_tex_plane_1_3 : texture_2d<f32>, ext_tex_params_3 : ExternalTextureParams) {
_ = textureSampleExternal(t, ext_tex_plane_1_2, s, vec2<f32>(1.0, 2.0), ext_tex_params_2);
_ = textureSampleExternal(t2, ext_tex_plane_1_3, s, vec2<f32>(1.0, 2.0), ext_tex_params_3);
}
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
@group(0) @binding(1) var smp : sampler;
@group(0) @binding(2) var ext_tex2 : texture_2d<f32>;
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
{{0, 0}, {{0, 3}, {0, 4}}},
{{0, 2}, {{0, 5}, {0, 6}}},
});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the texture_external passed to as a parameter to multiple
// functions produces the correct output.
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamNested) {
auto* src = R"(
fn nested(t : texture_external, s : sampler) {
_ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
fn f(t : texture_external, s : sampler) {
nested(t, s);
}
@group(0) @binding(0) var ext_tex : texture_external;
@group(0) @binding(1) var smp : sampler;
@fragment
fn main() {
f(ext_tex, smp);
}
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
fn nested(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
_ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
}
fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler) {
nested(t, ext_tex_plane_1_2, ext_tex_params_2, s);
}
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
@group(0) @binding(1) var smp : sampler;
@fragment
fn main() {
f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
{{0, 0}, {{0, 2}, {0, 3}}},
});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the texture_external passed to as a parameter to multiple functions produces the
// correct output.
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamNested_OutOfOrder) {
auto* src = R"(
fn nested(t : texture_external, s : sampler) {
_ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
fn f(t : texture_external, s : sampler) {
nested(t, s);
}
@group(0) @binding(0) var ext_tex : texture_external;
@group(0) @binding(1) var smp : sampler;
@fragment
fn main() {
f(ext_tex, smp);
}
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
fn nested(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
_ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
}
fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler) {
nested(t, ext_tex_plane_1_2, ext_tex_params_2, s);
}
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
@group(0) @binding(1) var smp : sampler;
@fragment
fn main() {
f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
{{0, 0}, {{0, 2}, {0, 3}}},
});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the transform works with a function using an external texture,
// even if there's no external texture declared at module scope.
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamWithoutGlobalDecl) {
auto* src = R"(
fn f(ext_tex : texture_external) -> vec2<u32> {
return textureDimensions(ext_tex);
}
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
fn f(ext_tex : texture_2d<f32>, ext_tex_plane_1 : texture_2d<f32>, ext_tex_params : ExternalTextureParams) -> vec2<u32> {
return (ext_tex_params.visibleSize + vec2<u32>(1));
}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the the transform handles aliases to external textures
TEST_F(MultiplanarExternalTextureTest, ExternalTextureAlias) {
auto* src = R"(
alias ET = texture_external;
fn f(t : ET, s : sampler) {
_ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
@group(0) @binding(0) var ext_tex : ET;
@group(0) @binding(1) var smp : sampler;
@fragment
fn main() {
f(ext_tex, smp);
}
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
alias ET = texture_external;
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
_ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
}
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
@group(0) @binding(1) var smp : sampler;
@fragment
fn main() {
f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
}
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
{{0, 0}, {{0, 2}, {0, 3}}},
});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
// Tests that the the transform handles aliases to external textures
TEST_F(MultiplanarExternalTextureTest, ExternalTextureAlias_OutOfOrder) {
auto* src = R"(
@fragment
fn main() {
f(ext_tex, smp);
}
fn f(t : ET, s : sampler) {
_ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
@group(0) @binding(0) var ext_tex : ET;
@group(0) @binding(1) var smp : sampler;
alias ET = texture_external;
)";
auto* expect = R"(
struct GammaTransferParams {
G : f32,
A : f32,
B : f32,
C : f32,
D : f32,
E : f32,
F : f32,
padding : u32,
}
struct ExternalTextureParams {
numPlanes : u32,
doYuvToRgbConversionOnly : u32,
yuvToRgbConversionMatrix : mat3x4<f32>,
gammaDecodeParams : GammaTransferParams,
gammaEncodeParams : GammaTransferParams,
gamutConversionMatrix : mat3x3<f32>,
sampleTransform : mat3x2<f32>,
loadTransform : mat3x2<f32>,
samplePlane0RectMin : vec2<f32>,
samplePlane0RectMax : vec2<f32>,
samplePlane1RectMin : vec2<f32>,
samplePlane1RectMax : vec2<f32>,
visibleSize : vec2<u32>,
plane1CoordFactor : vec2<f32>,
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
@fragment
fn main() {
f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
}
fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
let cond = (abs(v) < vec3<f32>(params.D));
let t = (sign(v) * ((params.C * abs(v)) + params.F));
let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
return select(f, t, cond);
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let modifiedCoords = (params.sampleTransform * vec3<f32>(coord, 1));
let plane0_clamped = clamp(modifiedCoords, params.samplePlane0RectMin, params.samplePlane0RectMax);
var color : vec4<f32>;
if ((params.numPlanes == 1)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0).rgba;
} else {
let plane1_clamped = clamp(modifiedCoords, params.samplePlane1RectMin, params.samplePlane1RectMax);
color = vec4<f32>((vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0).r, textureSampleLevel(plane1, smp, plane1_clamped, 0).rg, 1) * params.yuvToRgbConversionMatrix), 1);
}
if ((params.doYuvToRgbConversionOnly == 0)) {
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaDecodeParams), color.a);
color = vec4<f32>((params.gamutConversionMatrix * color.rgb), color.a);
color = vec4<f32>(gammaCorrection(color.rgb, params.gammaEncodeParams), color.a);
}
return color;
}
fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
_ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
}
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
@group(0) @binding(1) var smp : sampler;
alias ET = texture_external;
)";
DataMap data;
data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
{{0, 0}, {{0, 2}, {0, 3}}},
});
auto got = Run<MultiplanarExternalTexture>(src, data);
EXPECT_EQ(expect, str(got));
}
} // namespace
} // namespace tint::ast::transform