tint: Implement textureSampleBaseClampToEdge

Fixed: tint:1671
Change-Id: Iaae5b5d571a4401c0255de727245bf8dbbe06740
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/102642
Reviewed-by: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton
2022-09-22 22:59:16 +00:00
committed by Dawn LUCI CQ
parent 78f8067fd5
commit c4ebf2cc57
57 changed files with 6342 additions and 2854 deletions

View File

@@ -659,7 +659,9 @@ fn textureSampleLevel(texture: texture_depth_2d_array, sampler: sampler, coords:
fn textureSampleLevel(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: i32, level: i32, @const offset: vec2<i32>) -> f32
fn textureSampleLevel(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>, level: i32) -> f32
fn textureSampleLevel(texture: texture_depth_cube_array,sampler: sampler, coords: vec3<f32>, array_index: i32, level: i32) -> f32
fn textureSampleLevel(texture: texture_external, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
@deprecated fn textureSampleLevel(texture: texture_external, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
fn textureSampleBaseClampToEdge(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
fn textureSampleBaseClampToEdge(texture: texture_external, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
fn textureStore(texture: texture_storage_1d<f32_texel_format, write>, coords: i32, value: vec4<f32>)
fn textureStore(texture: texture_storage_2d<f32_texel_format, write>, coords: vec2<i32>, value: vec4<f32>)
fn textureStore(texture: texture_storage_2d_array<f32_texel_format, write>, coords: vec2<i32>, array_index: i32, value: vec4<f32>)

File diff suppressed because it is too large Load Diff

View File

@@ -57,11 +57,17 @@ bool IsDerivativeBuiltin(BuiltinType i) {
}
bool IsTextureBuiltin(BuiltinType i) {
return IsImageQueryBuiltin(i) || i == BuiltinType::kTextureLoad ||
i == BuiltinType::kTextureGather || i == BuiltinType::kTextureGatherCompare ||
i == BuiltinType::kTextureSample || i == BuiltinType::kTextureSampleLevel ||
i == BuiltinType::kTextureSampleBias || i == BuiltinType::kTextureSampleCompare ||
i == BuiltinType::kTextureSampleCompareLevel || i == BuiltinType::kTextureSampleGrad ||
return IsImageQueryBuiltin(i) || //
i == BuiltinType::kTextureGather || //
i == BuiltinType::kTextureGatherCompare || //
i == BuiltinType::kTextureLoad || //
i == BuiltinType::kTextureSample || //
i == BuiltinType::kTextureSampleBaseClampToEdge || //
i == BuiltinType::kTextureSampleBias || //
i == BuiltinType::kTextureSampleCompare || //
i == BuiltinType::kTextureSampleCompareLevel || //
i == BuiltinType::kTextureSampleGrad || //
i == BuiltinType::kTextureSampleLevel || //
i == BuiltinType::kTextureStore;
}

View File

@@ -318,6 +318,9 @@ BuiltinType ParseBuiltinType(const std::string& name) {
if (name == "textureSampleLevel") {
return BuiltinType::kTextureSampleLevel;
}
if (name == "textureSampleBaseClampToEdge") {
return BuiltinType::kTextureSampleBaseClampToEdge;
}
if (name == "textureStore") {
return BuiltinType::kTextureStore;
}
@@ -558,6 +561,8 @@ const char* str(BuiltinType i) {
return "textureSampleGrad";
case BuiltinType::kTextureSampleLevel:
return "textureSampleLevel";
case BuiltinType::kTextureSampleBaseClampToEdge:
return "textureSampleBaseClampToEdge";
case BuiltinType::kTextureStore:
return "textureStore";
case BuiltinType::kTextureLoad:

View File

@@ -128,6 +128,7 @@ enum class BuiltinType {
kTextureSampleCompareLevel,
kTextureSampleGrad,
kTextureSampleLevel,
kTextureSampleBaseClampToEdge,
kTextureStore,
kTextureLoad,
kAtomicLoad,

View File

@@ -34,7 +34,7 @@ CallTarget::CallTarget(const CallTarget&) = default;
CallTarget::~CallTarget() = default;
CallTargetSignature::CallTargetSignature(const sem::Type* ret_ty,
utils::VectorRef<const Parameter*> params)
utils::VectorRef<const sem::Parameter*> params)
: return_type(ret_ty), parameters(std::move(params)) {}
CallTargetSignature::CallTargetSignature(const CallTargetSignature&) = default;
CallTargetSignature::~CallTargetSignature() = default;

View File

@@ -57,6 +57,14 @@ struct CallTargetSignature {
/// @returns the index of the parameter with the given usage, or -1 if no
/// parameter with the given usage exists.
int IndexOf(ParameterUsage usage) const;
/// @param usage the parameter usage to find
/// @returns the the parameter with the given usage, or nullptr if no parameter with the given
/// usage exists.
inline const sem::Parameter* Parameter(ParameterUsage usage) const {
auto idx = IndexOf(usage);
return (idx >= 0) ? parameters[static_cast<size_t>(idx)] : nullptr;
}
};
/// CallTarget is the base for callable functions, builtins, type constructors

View File

@@ -512,6 +512,29 @@ struct BuiltinPolyfill::State {
return name;
}
/// Builds the polyfill function for the `textureSampleBaseClampToEdge` builtin, when the
/// texture type is texture_2d<f32>.
/// @return the polyfill function name
Symbol textureSampleBaseClampToEdge_2d_f32() {
auto name = b.Symbols().New("tint_textureSampleBaseClampToEdge");
auto body = utils::Vector{
b.Decl(b.Let("dims",
b.Construct(b.ty.vec2<f32>(), b.Call("textureDimensions", "t", 0_a)))),
b.Decl(b.Let("half_texel", b.Div(b.vec2<f32>(0.5_a), "dims"))),
b.Decl(
b.Let("clamped", b.Call("clamp", "coord", "half_texel", b.Sub(1_a, "half_texel")))),
b.Return(b.Call("textureSampleLevel", "t", "s", "clamped", 0_a)),
};
b.Func(name,
utils::Vector{
b.Param("t", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
b.Param("s", b.ty.sampler(ast::SamplerKind::kSampler)),
b.Param("coord", b.ty.vec2<f32>()),
},
b.ty.vec4<f32>(), body);
return name;
}
private:
/// @returns the AST type for the given sem type
const ast::Type* T(const sem::Type* ty) const { return CreateASTTypeFor(ctx, ty); }
@@ -597,6 +620,15 @@ bool BuiltinPolyfill::ShouldRun(const Program* program, const DataMap& data) con
return true;
}
break;
case sem::BuiltinType::kTextureSampleBaseClampToEdge:
if (builtins.texture_sample_base_clamp_to_edge_2d_f32) {
auto& sig = builtin->Signature();
auto* tex = sig.Parameter(sem::ParameterUsage::kTexture);
if (auto* stex = tex->Type()->As<sem::SampledTexture>()) {
return stex->type()->Is<sem::F32>();
}
}
break;
default:
break;
}
@@ -690,6 +722,19 @@ void BuiltinPolyfill::Run(CloneContext& ctx, const DataMap& data, DataMap&) cons
});
}
break;
case sem::BuiltinType::kTextureSampleBaseClampToEdge:
if (builtins.texture_sample_base_clamp_to_edge_2d_f32) {
auto& sig = builtin->Signature();
auto* tex = sig.Parameter(sem::ParameterUsage::kTexture);
if (auto* stex = tex->Type()->As<sem::SampledTexture>()) {
if (stex->type()->Is<sem::F32>()) {
polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
return s.textureSampleBaseClampToEdge_2d_f32();
});
}
}
}
break;
default:
break;
}

View File

@@ -61,6 +61,8 @@ class BuiltinPolyfill final : public Castable<BuiltinPolyfill, Transform> {
Level insert_bits = Level::kNone;
/// Should `saturate()` be polyfilled?
bool saturate = false;
/// Should `textureSampleBaseClampToEdge()` be polyfilled for texture_2d<f32> textures?
bool texture_sample_base_clamp_to_edge_2d_f32 = false;
};
/// Config is consumed by the BuiltinPolyfill transform.

View File

@@ -1549,5 +1549,76 @@ fn f() {
EXPECT_EQ(expect, str(got));
}
////////////////////////////////////////////////////////////////////////////////
// textureSampleBaseClampToEdge
////////////////////////////////////////////////////////////////////////////////
DataMap polyfillTextureSampleBaseClampToEdge_2d_f32() {
BuiltinPolyfill::Builtins builtins;
builtins.texture_sample_base_clamp_to_edge_2d_f32 = true;
DataMap data;
data.Add<BuiltinPolyfill::Config>(builtins);
return data;
}
TEST_F(BuiltinPolyfillTest, ShouldRunTextureSampleBaseClampToEdge_2d_f32) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;
fn f() {
textureSampleBaseClampToEdge(t, s, vec2<f32>(0.5));
}
)";
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillTextureSampleBaseClampToEdge_2d_f32()));
}
TEST_F(BuiltinPolyfillTest, ShouldRunTextureSampleBaseClampToEdge_external) {
auto* src = R"(
@group(0) @binding(0) var t : texture_external;
@group(0) @binding(1) var s : sampler;
fn f() {
textureSampleBaseClampToEdge(t, s, vec2<f32>(0.5));
}
)";
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillTextureSampleBaseClampToEdge_2d_f32()));
}
TEST_F(BuiltinPolyfillTest, TextureSampleBaseClampToEdge_2d_f32_f32) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;
fn f() {
let r = textureSampleBaseClampToEdge(t, s, vec2<f32>(0.5));
}
)";
auto* expect = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;
fn tint_textureSampleBaseClampToEdge(t : texture_2d<f32>, s : sampler, coord : vec2<f32>) -> vec4<f32> {
let dims = vec2<f32>(textureDimensions(t, 0));
let half_texel = (vec2<f32>(0.5) / dims);
let clamped = clamp(coord, half_texel, (1 - half_texel));
return textureSampleLevel(t, s, clamped, 0);
}
fn f() {
let r = tint_textureSampleBaseClampToEdge(t, s, vec2<f32>(0.5));
}
)";
auto got = Run<BuiltinPolyfill>(src, polyfillTextureSampleBaseClampToEdge_2d_f32());
EXPECT_EQ(expect, str(got));
}
} // namespace
} // namespace tint::transform

View File

@@ -31,8 +31,8 @@ using namespace tint::number_suffixes; // NOLINT
namespace tint::transform {
namespace {
/// This struct stores symbols for new bindings created as a result of
/// transforming a texture_external instance.
/// This struct stores symbols for new bindings created as a result of transforming a
/// texture_external instance.
struct NewBindingSymbols {
Symbol params;
Symbol plane_0;
@@ -64,11 +64,14 @@ struct MultiplanarExternalTexture::State {
/// Symbol for the textureSampleExternal function
Symbol texture_sample_external_sym;
/// Symbol for the textureSampleExternalDEPRECATED function
Symbol texture_sample_external_deprecated_sym;
/// Symbol for the gammaCorrection function
Symbol gamma_correction_sym;
/// Storage for new bindings that have been created corresponding to an
/// original texture_external binding.
/// Storage for new bindings that have been created corresponding to an original
/// texture_external binding.
std::unordered_map<const sem::Variable*, NewBindingSymbols> new_binding_symbols;
/// Constructor
@@ -82,33 +85,30 @@ struct MultiplanarExternalTexture::State {
void Process() {
auto& sem = ctx.src->Sem();
// For each texture_external binding, we replace it with a texture_2d<f32>
// binding and create two additional bindings (one texture_2d<f32> to
// represent the secondary plane and one uniform buffer for the
// ExternalTextureParams struct).
// For each texture_external binding, we replace it with a texture_2d<f32> binding and
// create two additional bindings (one texture_2d<f32> to represent the secondary plane and
// one uniform buffer for the ExternalTextureParams struct).
for (auto* global : ctx.src->AST().GlobalVariables()) {
auto* sem_var = sem.Get<sem::GlobalVariable>(global);
if (!sem_var->Type()->UnwrapRef()->Is<sem::ExternalTexture>()) {
continue;
}
// If the attributes are empty, then this must be a texture_external
// passed as a function parameter. These variables are transformed
// elsewhere.
// If the attributes are empty, then this must be a texture_external passed as a
// function parameter. These variables are transformed elsewhere.
if (global->attributes.IsEmpty()) {
continue;
}
// If we find a texture_external binding, we know we must emit the
// ExternalTextureParams struct.
// If we find a texture_external binding, we know we must emit the ExternalTextureParams
// struct.
if (!params_struct_sym.IsValid()) {
createExtTexParamsStructs();
}
// The binding points for the newly introduced bindings must have been
// provided to this transform. We fetch the new binding points by
// providing the original texture_external binding points into the
// passed map.
// The binding points for the newly introduced bindings must have been provided to this
// transform. We fetch the new binding points by providing the original texture_external
// binding points into the passed map.
BindingPoint bp = sem_var->BindingPoint();
BindingsMap::const_iterator it = new_binding_points->bindings_map.find(bp);
@@ -122,10 +122,9 @@ struct MultiplanarExternalTexture::State {
BindingPoints bps = it->second;
// Symbols for the newly created bindings must be saved so they can be
// passed as parameters later. These are placed in a map and keyed by
// the source symbol associated with the texture_external binding that
// corresponds with the new destination bindings.
// Symbols for the newly created bindings must be saved so they can be passed as
// parameters later. These are placed in a map and keyed by the source symbol associated
// with the texture_external binding that corresponds with the new destination bindings.
// NewBindingSymbols new_binding_syms;
auto& syms = new_binding_symbols[sem_var];
syms.plane_0 = ctx.Clone(global->symbol);
@@ -137,8 +136,7 @@ struct MultiplanarExternalTexture::State {
ast::StorageClass::kUniform, b.Group(AInt(bps.params.group)),
b.Binding(AInt(bps.params.binding)));
// Replace the original texture_external binding with a texture_2d<f32>
// binding.
// Replace the original texture_external binding with a texture_2d<f32> binding.
auto cloned_attributes = ctx.Clone(global->attributes);
const ast::Expression* cloned_constructor = ctx.Clone(global->constructor);
@@ -148,23 +146,22 @@ struct MultiplanarExternalTexture::State {
ctx.Replace(global, replacement);
}
// We must update all the texture_external parameters for user declared
// functions.
// We must update all the texture_external parameters for user declared functions.
for (auto* fn : ctx.src->AST().Functions()) {
for (const ast::Variable* param : fn->params) {
if (auto* sem_var = sem.Get(param)) {
if (!sem_var->Type()->UnwrapRef()->Is<sem::ExternalTexture>()) {
continue;
}
// If we find a texture_external, we must ensure the
// ExternalTextureParams struct exists.
// If we find a texture_external, we must ensure the ExternalTextureParams
// struct exists.
if (!params_struct_sym.IsValid()) {
createExtTexParamsStructs();
}
// When a texture_external is found, we insert all components
// the texture_external into the parameter list. We must also place
// the new symbols into the transform state so they can be used when
// transforming function calls.
// When a texture_external is found, we insert all components the
// texture_external into the parameter list. We must also place the new symbols
// into the transform state so they can be used when transforming function
// calls.
auto& syms = new_binding_symbols[sem_var];
syms.plane_0 = ctx.Clone(param->symbol);
syms.plane_1 = b.Symbols().New("ext_tex_plane_1");
@@ -180,8 +177,8 @@ struct MultiplanarExternalTexture::State {
}
}
// Transform the original textureLoad and textureSampleLevel calls into
// textureLoadExternal and textureSampleExternal calls.
// Transform the external texture builtin calls into calls to the external texture
// functions.
ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::CallExpression* {
auto* call = sem.Get(expr)->UnwrapMaterialize()->As<sem::Call>();
auto* builtin = call->Target()->As<sem::Builtin>();
@@ -192,28 +189,29 @@ struct MultiplanarExternalTexture::State {
if (auto* var_user = sem.Get<sem::VariableUser>(expr->args[0])) {
auto it = new_binding_symbols.find(var_user->Variable());
if (it == new_binding_symbols.end()) {
// If valid new binding locations were not provided earlier, we
// would have been unable to create these symbols. An error
// message was emitted earlier, so just return early to avoid
// internal compiler errors and retain a clean error message.
// If valid new binding locations were not provided earlier, we would have
// been unable to create these symbols. An error message was emitted
// earlier, so just return early to avoid internal compiler errors and
// retain a clean error message.
return nullptr;
}
auto& syms = it->second;
if (builtin->Type() == sem::BuiltinType::kTextureLoad) {
return createTexLdExt(expr, syms);
}
if (builtin->Type() == sem::BuiltinType::kTextureSampleLevel) {
return createTexSmpExt(expr, syms);
switch (builtin->Type()) {
case sem::BuiltinType::kTextureLoad:
return createTextureLoad(expr, syms);
case sem::BuiltinType::kTextureSampleLevel:
return createTextureSampleLevel(expr, syms);
case sem::BuiltinType::kTextureSampleBaseClampToEdge:
return createTextureSampleBaseClampToEdge(expr, syms);
default:
break;
}
}
} else if (call->Target()->Is<sem::Function>()) {
// The call expression may be to a user-defined function that
// contains a texture_external parameter. These need to be expanded
// out to multiple plane textures and the texture parameters
// structure.
// The call expression may be to a user-defined function that contains a
// texture_external parameter. These need to be expanded out to multiple plane
// textures and the texture parameters structure.
for (auto* arg : expr->args) {
if (auto* var_user = sem.Get<sem::VariableUser>(arg)) {
// Check if a parameter is a texture_external by trying to find
@@ -296,38 +294,69 @@ struct MultiplanarExternalTexture::State {
});
}
/// Constructs a StatementList containing all the statements making up the
/// bodies of the textureSampleExternal and textureLoadExternal functions.
/// Constructs a StatementList containing all the statements making up the body of the texture
/// builtin function.
/// @param call_type determines which function body to generate
/// @returns a statement list that makes of the body of the chosen function
auto createTexFnExtStatementList(sem::BuiltinType call_type) {
auto buildTextureBuiltinBody(sem::BuiltinType call_type) {
utils::Vector<const ast::Statement*, 16> stmts;
const ast::CallExpression* single_plane_call = nullptr;
const ast::CallExpression* plane_0_call = nullptr;
const ast::CallExpression* plane_1_call = nullptr;
if (call_type == sem::BuiltinType::kTextureSampleLevel) {
// textureSampleLevel(plane0, smp, coord.xy, 0.0);
single_plane_call = b.Call("textureSampleLevel", "plane0", "smp", "coord", 0_f);
// textureSampleLevel(plane0, smp, coord.xy, 0.0);
plane_0_call = b.Call("textureSampleLevel", "plane0", "smp", "coord", 0_f);
// textureSampleLevel(plane1, smp, coord.xy, 0.0);
plane_1_call = b.Call("textureSampleLevel", "plane1", "smp", "coord", 0_f);
} else if (call_type == sem::BuiltinType::kTextureLoad) {
// textureLoad(plane0, coords.xy, 0);
single_plane_call = b.Call("textureLoad", "plane0", "coord", 0_i);
// textureLoad(plane0, coords.xy, 0);
plane_0_call = b.Call("textureLoad", "plane0", "coord", 0_i);
// textureLoad(plane1, coords.xy, 0);
plane_1_call = b.Call("textureLoad", "plane1", "coord", 0_i);
} else {
TINT_ICE(Transform, b.Diagnostics()) << "unhandled builtin: " << call_type;
switch (call_type) {
case sem::BuiltinType::kTextureSampleLevel:
// TODO(crbug.com/tint/1671): DEPRECATED
// textureSampleLevel(plane0, smp, coord, 0.0);
single_plane_call = b.Call("textureSampleLevel", "plane0", "smp", "coord", 0_f);
// textureSampleLevel(plane0, smp, coord, 0.0);
plane_0_call = b.Call("textureSampleLevel", "plane0", "smp", "coord", 0_f);
// textureSampleLevel(plane1, smp, coord, 0.0);
plane_1_call = b.Call("textureSampleLevel", "plane1", "smp", "coord", 0_f);
break;
case sem::BuiltinType::kTextureSampleBaseClampToEdge:
stmts.Push(b.Decl(b.Let(
"plane0_dims",
b.Construct(b.ty.vec2<f32>(), b.Call("textureDimensions", "plane0", 0_a)))));
stmts.Push(
b.Decl(b.Let("plane0_half_texel", b.Div(b.vec2<f32>(0.5_a), "plane0_dims"))));
stmts.Push(
b.Decl(b.Let("plane0_clamped", b.Call("clamp", "coord", "plane0_half_texel",
b.Sub(1_a, "plane0_half_texel")))));
stmts.Push(b.Decl(b.Let(
"plane1_dims",
b.Construct(b.ty.vec2<f32>(), b.Call("textureDimensions", "plane1", 0_a)))));
stmts.Push(
b.Decl(b.Let("plane1_half_texel", b.Div(b.vec2<f32>(0.5_a), "plane1_dims"))));
stmts.Push(
b.Decl(b.Let("plane1_clamped", b.Call("clamp", "coord", "plane1_half_texel",
b.Sub(1_a, "plane1_half_texel")))));
// textureSampleLevel(plane0, smp, plane0_clamped, 0.0);
single_plane_call =
b.Call("textureSampleLevel", "plane0", "smp", "plane0_clamped", 0_f);
// textureSampleLevel(plane0, smp, plane0_clamped, 0.0);
plane_0_call = b.Call("textureSampleLevel", "plane0", "smp", "plane0_clamped", 0_f);
// textureSampleLevel(plane1, smp, plane1_clamped, 0.0);
plane_1_call = b.Call("textureSampleLevel", "plane1", "smp", "plane1_clamped", 0_f);
break;
case sem::BuiltinType::kTextureLoad:
// textureLoad(plane0, coord, 0);
single_plane_call = b.Call("textureLoad", "plane0", "coord", 0_i);
// textureLoad(plane0, coord, 0);
plane_0_call = b.Call("textureLoad", "plane0", "coord", 0_i);
// textureLoad(plane1, coord, 0);
plane_1_call = b.Call("textureLoad", "plane1", "coord", 0_i);
break;
default:
TINT_ICE(Transform, b.Diagnostics()) << "unhandled builtin: " << call_type;
}
return utils::Vector{
// var color: vec3<f32>;
b.Decl(b.Var("color", b.ty.vec3(b.ty.f32()))),
// if ((params.numPlanes == 1u))
b.If(b.create<ast::BinaryExpression>(
ast::BinaryOp::kEqual, b.MemberAccessor("params", "numPlanes"), b.Expr(1_u)),
// var color: vec3<f32>;
stmts.Push(b.Decl(b.Var("color", b.ty.vec3(b.ty.f32()))));
// if ((params.numPlanes == 1u))
stmts.Push(
b.If(b.Equal(b.MemberAccessor("params", "numPlanes"), b.Expr(1_u)),
b.Block(
// color = textureLoad(plane0, coord, 0).rgb;
b.Assign("color", b.MemberAccessor(single_plane_call, "rgb"))),
@@ -337,11 +366,11 @@ struct MultiplanarExternalTexture::State {
b.Assign("color",
b.Mul(b.vec4<f32>(b.MemberAccessor(plane_0_call, "r"),
b.MemberAccessor(plane_1_call, "rg"), 1_f),
b.MemberAccessor("params", "yuvToRgbConversionMatrix")))))),
// if (params.doYuvToRgbConversionOnly == 0u)
b.If(b.create<ast::BinaryExpression>(
ast::BinaryOp::kEqual, b.MemberAccessor("params", "doYuvToRgbConversionOnly"),
b.Expr(0_u)),
b.MemberAccessor("params", "yuvToRgbConversionMatrix")))))));
// if (params.doYuvToRgbConversionOnly == 0u)
stmts.Push(
b.If(b.Equal(b.MemberAccessor("params", "doYuvToRgbConversionOnly"), b.Expr(0_u)),
b.Block(
// color = gammaConversion(color, gammaDecodeParams);
b.Assign("color", b.Call("gammaCorrection", "color",
@@ -351,18 +380,21 @@ struct MultiplanarExternalTexture::State {
b.Mul(b.MemberAccessor("params", "gamutConversionMatrix"), "color")),
// color = gammaConversion(color, gammaEncodeParams);
b.Assign("color", b.Call("gammaCorrection", "color",
b.MemberAccessor("params", "gammaEncodeParams"))))),
// return vec4<f32>(color, 1.f);
b.Return(b.vec4<f32>("color", 1_f))};
b.MemberAccessor("params", "gammaEncodeParams"))))));
// return vec4<f32>(color, 1.f);
stmts.Push(b.Return(b.vec4<f32>("color", 1_f)));
return stmts;
}
/// Creates the textureSampleExternal function if needed and returns a call
/// expression to it.
/// Creates the textureSampleExternal function if needed and returns a call expression to it.
/// TODO(crbug.com/tint/1671): DEPRECATED: Replaced with createTextureSampleBaseClampToEdge().
/// @param expr the call expression being transformed
/// @param syms the expanded symbols to be used in the new call
/// @returns a call expression to textureSampleExternal
const ast::CallExpression* createTexSmpExt(const ast::CallExpression* expr,
NewBindingSymbols syms) {
const ast::CallExpression* createTextureSampleLevel(const ast::CallExpression* expr,
NewBindingSymbols syms) {
const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
if (expr->args.Length() != 3) {
@@ -391,9 +423,7 @@ struct MultiplanarExternalTexture::State {
b.Param("params", b.ty.type_name(params_struct_sym)),
},
b.ty.vec4(b.ty.f32()),
utils::Vector{
createTexFnExtStatementList(sem::BuiltinType::kTextureSampleLevel),
});
buildTextureBuiltinBody(sem::BuiltinType::kTextureSampleLevel));
}
const ast::IdentifierExpression* exp = b.Expr(texture_sample_external_sym);
@@ -406,13 +436,60 @@ struct MultiplanarExternalTexture::State {
});
}
/// Creates the textureLoadExternal function if needed and returns a call
/// expression to it.
/// Creates the textureSampleExternal function if needed and returns a call expression to it.
/// @param expr the call expression being transformed
/// @param syms the expanded symbols to be used in the new call
/// @returns a call expression to textureSampleExternal
const ast::CallExpression* createTextureSampleBaseClampToEdge(const ast::CallExpression* expr,
NewBindingSymbols syms) {
const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
if (expr->args.Length() != 3) {
TINT_ICE(Transform, b.Diagnostics())
<< "expected textureSampleBaseClampToEdge call with a "
"texture_external to have 3 parameters, found "
<< expr->args.Length() << " parameters";
}
// TextureSampleExternal calls the gammaCorrection function, so ensure it
// exists.
if (!gamma_correction_sym.IsValid()) {
createGammaCorrectionFn();
}
if (!texture_sample_external_sym.IsValid()) {
texture_sample_external_sym = b.Symbols().New("textureSampleExternal");
// Emit the textureSampleExternal function.
b.Func(
texture_sample_external_sym,
utils::Vector{
b.Param("plane0", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
b.Param("plane1", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
b.Param("smp", b.ty.sampler(ast::SamplerKind::kSampler)),
b.Param("coord", b.ty.vec2(b.ty.f32())),
b.Param("params", b.ty.type_name(params_struct_sym)),
},
b.ty.vec4(b.ty.f32()),
buildTextureBuiltinBody(sem::BuiltinType::kTextureSampleBaseClampToEdge));
}
const ast::IdentifierExpression* exp = b.Expr(texture_sample_external_sym);
return b.Call(exp, utils::Vector{
plane_0_binding_param,
b.Expr(syms.plane_1),
ctx.Clone(expr->args[1]),
ctx.Clone(expr->args[2]),
b.Expr(syms.params),
});
}
/// Creates the textureLoadExternal function if needed and returns a call expression to it.
/// @param expr the call expression being transformed
/// @param syms the expanded symbols to be used in the new call
/// @returns a call expression to textureLoadExternal
const ast::CallExpression* createTexLdExt(const ast::CallExpression* expr,
NewBindingSymbols syms) {
const ast::CallExpression* createTextureLoad(const ast::CallExpression* expr,
NewBindingSymbols syms) {
const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
if (expr->args.Length() != 2) {
@@ -440,10 +517,8 @@ struct MultiplanarExternalTexture::State {
b.Param("coord", b.ty.vec2(b.ty.i32())),
b.Param("params", b.ty.type_name(params_struct_sym)),
},
b.ty.vec4(b.ty.f32()),
utils::Vector{
createTexFnExtStatementList(sem::BuiltinType::kTextureLoad),
});
b.ty.vec4(b.ty.f32()), //
buildTextureBuiltinBody(sem::BuiltinType::kTextureLoad));
}
return b.Call(texture_load_external_sym, plane_0_binding_param, syms.plane_1,
@@ -469,13 +544,11 @@ bool MultiplanarExternalTexture::ShouldRun(const Program* program, const DataMap
return false;
}
// Within this transform, an instance of a texture_external binding is unpacked
// into two texture_2d<f32> bindings representing two possible planes of a
// single texture and a uniform buffer binding representing a struct of
// parameters. Calls to textureLoad or textureSampleLevel that contain a
// texture_external parameter will be transformed into a newly generated version
// of the function, which can perform the desired operation on a single RGBA
// plane or on separate Y and UV planes.
// Within this transform, an instance of a texture_external binding is unpacked into two
// texture_2d<f32> bindings representing two possible planes of a single texture and a uniform
// buffer binding representing a struct of parameters. Calls to texture builtins that contain a
// texture_external parameter will be transformed into a newly generated version of the function,
// which can perform the desired operation on a single RGBA plane or on separate Y and UV planes.
void MultiplanarExternalTexture::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) const {
auto* new_binding_points = inputs.Get<NewBindingPoints>();

View File

@@ -49,9 +49,8 @@ fn f(ext_tex : texture_external) {}
EXPECT_TRUE(ShouldRun<MultiplanarExternalTexture>(src));
}
// Running the transform without passing in data for the new bindings should
// result in an error.
TEST_F(MultiplanarExternalTextureTest, ErrorNoPassedData) {
// Running the transform without passing in data for the new bindings should result in an error.
TEST_F(MultiplanarExternalTextureTest, ErrorNoPassedData_SampleLevel) {
auto* src = R"(
@group(0) @binding(0) var s : sampler;
@group(0) @binding(1) var ext_tex : texture_external;
@@ -68,8 +67,26 @@ fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
EXPECT_EQ(expect, str(got));
}
// 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 =
R"(error: missing new binding point data for tint::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) {
TEST_F(MultiplanarExternalTextureTest, ErrorIncorrectBindingPont_SampleLevel) {
auto* src = R"(
@group(0) @binding(0) var s : sampler;
@group(0) @binding(1) var ext_tex : texture_external;
@@ -91,6 +108,29 @@ fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
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"(
@@ -277,6 +317,88 @@ fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
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>,
}
@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 plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
color = (params.gamutConversionMatrix * color);
color = gammaCorrection(color, params.gammaEncodeParams);
}
return vec4<f32>(color, 1.0f);
}
@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 textureSampleLevel call.
TEST_F(MultiplanarExternalTextureTest, BasicTextureSampleLevel_OutOfOrder) {
auto* src = R"(
@@ -353,6 +475,88 @@ fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
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>,
}
@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 plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
color = (params.gamutConversionMatrix * color);
color = gammaCorrection(color, params.gammaEncodeParams);
}
return vec4<f32>(color, 1.0f);
}
@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"(
@@ -499,8 +703,7 @@ fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
EXPECT_EQ(expect, str(got));
}
// Tests that the transform works with both a textureSampleLevel and textureLoad
// call.
// Tests that the transform works with both a textureSampleLevel and textureLoad call.
TEST_F(MultiplanarExternalTextureTest, TextureSampleAndTextureLoad) {
auto* src = R"(
@group(0) @binding(0) var s : sampler;
@@ -591,8 +794,104 @@ fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
EXPECT_EQ(expect, str(got));
}
// Tests that the transform works with both a textureSampleLevel and textureLoad
// call.
// 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>,
}
@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 plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
color = (params.gamutConversionMatrix * color);
color = gammaCorrection(color, params.gammaEncodeParams);
}
return vec4<f32>(color, 1.0f);
}
fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureLoad(plane0, coord, 0i).rgb;
} else {
color = (vec4<f32>(textureLoad(plane0, coord, 0i).r, textureLoad(plane1, coord, 0i).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
color = (params.gamutConversionMatrix * color);
color = gammaCorrection(color, params.gammaEncodeParams);
}
return vec4<f32>(color, 1.0f);
}
@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 textureSampleLevel and textureLoad call.
TEST_F(MultiplanarExternalTextureTest, TextureSampleAndTextureLoad_OutOfOrder) {
auto* src = R"(
@fragment
@@ -683,6 +982,103 @@ fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
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>,
}
@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 plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
color = (params.gamutConversionMatrix * color);
color = gammaCorrection(color, params.gammaEncodeParams);
}
return vec4<f32>(color, 1.0f);
}
fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureLoad(plane0, coord, 0i).rgb;
} else {
color = (vec4<f32>(textureLoad(plane0, coord, 0i).r, textureLoad(plane1, coord, 0i).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
color = (params.gamutConversionMatrix * color);
color = gammaCorrection(color, params.gammaEncodeParams);
}
return vec4<f32>(color, 1.0f);
}
@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, ManyTextureSampleLevel) {
auto* src = R"(
@@ -784,12 +1180,122 @@ fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
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>,
}
@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 plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
color = (params.gamutConversionMatrix * color);
color = gammaCorrection(color, params.gammaEncodeParams);
}
return vec4<f32>(color, 1.0f);
}
@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) {
textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
@group(0) @binding(0) var ext_tex : texture_external;
@@ -834,11 +1340,17 @@ fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, coord, 0.0f).rgb;
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
@@ -879,7 +1391,7 @@ fn main() {
}
fn f(t : texture_external, s : sampler) {
textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
@group(0) @binding(0) var ext_tex : texture_external;
@@ -924,11 +1436,17 @@ fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, coord, 0.0f).rgb;
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
@@ -959,7 +1477,7 @@ fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsSecondParam) {
auto* src = R"(
fn f(s : sampler, t : texture_external) {
textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
@group(0) @binding(0) var ext_tex : texture_external;
@@ -1004,11 +1522,17 @@ fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, coord, 0.0f).rgb;
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
@@ -1044,8 +1568,8 @@ fn main() {
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamMultiple) {
auto* src = R"(
fn f(t : texture_external, s : sampler, t2 : texture_external) {
textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
textureSampleLevel(t2, s, vec2<f32>(1.0, 2.0));
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;
@@ -1095,11 +1619,17 @@ fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, coord, 0.0f).rgb;
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
@@ -1144,8 +1674,8 @@ fn main() {
}
fn f(t : texture_external, s : sampler, t2 : texture_external) {
textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
textureSampleLevel(t2, s, vec2<f32>(1.0, 2.0));
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;
@@ -1196,11 +1726,17 @@ fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, coord, 0.0f).rgb;
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
@@ -1235,7 +1771,7 @@ fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamNested) {
auto* src = R"(
fn nested(t : texture_external, s : sampler) {
textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
fn f(t : texture_external, s : sampler) {
@@ -1284,11 +1820,17 @@ fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, coord, 0.0f).rgb;
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
@@ -1323,12 +1865,12 @@ fn main() {
EXPECT_EQ(expect, str(got));
}
// Tests that the texture_external passed to as a parameter to multiple
// functions produces the correct output.
// 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) {
textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
fn f(t : texture_external, s : sampler) {
@@ -1377,11 +1919,17 @@ fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, coord, 0.0f).rgb;
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
@@ -1464,7 +2012,7 @@ TEST_F(MultiplanarExternalTextureTest, ExternalTextureAlias) {
type ET = texture_external;
fn f(t : ET, s : sampler) {
textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
@group(0) @binding(0) var ext_tex : ET;
@@ -1511,11 +2059,17 @@ fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, coord, 0.0f).rgb;
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);
@@ -1555,7 +2109,7 @@ fn main() {
}
fn f(t : ET, s : sampler) {
textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
}
@group(0) @binding(0) var ext_tex : ET;
@@ -1602,11 +2156,17 @@ fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
}
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
let plane0_clamped = clamp(coord, plane0_half_texel, (1 - plane0_half_texel));
let plane1_dims = vec2<f32>(textureDimensions(plane1, 0));
let plane1_half_texel = (vec2<f32>(0.5) / plane1_dims);
let plane1_clamped = clamp(coord, plane1_half_texel, (1 - plane1_half_texel));
var color : vec3<f32>;
if ((params.numPlanes == 1u)) {
color = textureSampleLevel(plane0, smp, coord, 0.0f).rgb;
color = textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).rgb;
} else {
color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0f).r, textureSampleLevel(plane1, smp, coord, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
color = (vec4<f32>(textureSampleLevel(plane0, smp, plane0_clamped, 0.0f).r, textureSampleLevel(plane1, smp, plane1_clamped, 0.0f).rg, 1.0f) * params.yuvToRgbConversionMatrix);
}
if ((params.doYuvToRgbConversionOnly == 0u)) {
color = gammaCorrection(color, params.gammaDecodeParams);

View File

@@ -192,6 +192,7 @@ SanitizedResult Sanitize(const Program* in,
polyfills.first_trailing_bit = true;
polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
polyfills.saturate = true;
polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
data.Add<transform::BuiltinPolyfill::Config>(polyfills);
manager.Add<transform::BuiltinPolyfill>();
}

View File

@@ -175,6 +175,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
polyfills.first_leading_bit = true;
polyfills.first_trailing_bit = true;
polyfills.insert_bits = transform::BuiltinPolyfill::Level::kFull;
polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
data.Add<transform::BuiltinPolyfill::Config>(polyfills);
manager.Add<transform::BuiltinPolyfill>();
}

View File

@@ -172,6 +172,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
polyfills.first_leading_bit = true;
polyfills.first_trailing_bit = true;
polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
data.Add<transform::BuiltinPolyfill::Config>(polyfills);
manager.Add<transform::BuiltinPolyfill>();
}

View File

@@ -58,6 +58,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
polyfills.first_trailing_bit = true;
polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
polyfills.saturate = true;
polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
data.Add<transform::BuiltinPolyfill::Config>(polyfills);
manager.Add<transform::BuiltinPolyfill>();
}