Transform texture_externals used in a user-defined function
Adds functionality and tests for performing the multiplanar external texture transform on texture_external parameters in user-defined functions. Bug: dawn:1082 Change-Id: I15f23e639a6cd24ed3428055420908f05b69c0c6 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/70840 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com> Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
abf4f17b8e
commit
f71784fc2b
|
@ -20,6 +20,7 @@
|
||||||
#include "src/ast/function.h"
|
#include "src/ast/function.h"
|
||||||
#include "src/program_builder.h"
|
#include "src/program_builder.h"
|
||||||
#include "src/sem/call.h"
|
#include "src/sem/call.h"
|
||||||
|
#include "src/sem/function.h"
|
||||||
#include "src/sem/variable.h"
|
#include "src/sem/variable.h"
|
||||||
|
|
||||||
TINT_INSTANTIATE_TYPEINFO(tint::transform::MultiplanarExternalTexture);
|
TINT_INSTANTIATE_TYPEINFO(tint::transform::MultiplanarExternalTexture);
|
||||||
|
@ -33,15 +34,26 @@ namespace {
|
||||||
/// This struct stores symbols for new bindings created as a result of
|
/// This struct stores symbols for new bindings created as a result of
|
||||||
/// transforming a texture_external instance.
|
/// transforming a texture_external instance.
|
||||||
struct NewBindingSymbols {
|
struct NewBindingSymbols {
|
||||||
Symbol ext_tex_params_binding_sym;
|
Symbol params;
|
||||||
Symbol ext_tex_plane_1_binding_sym;
|
Symbol plane_0;
|
||||||
|
Symbol plane_1;
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
/// State holds the current transform state
|
/// State holds the current transform state
|
||||||
struct MultiplanarExternalTexture::State {
|
struct MultiplanarExternalTexture::State {
|
||||||
|
/// The clone context.
|
||||||
|
CloneContext& ctx;
|
||||||
|
|
||||||
|
/// ProgramBuilder for the context
|
||||||
|
ProgramBuilder& b;
|
||||||
|
|
||||||
|
/// Desination binding locations for the expanded texture_external provided as
|
||||||
|
/// input into the transform.
|
||||||
|
const NewBindingPoints* new_binding_points;
|
||||||
|
|
||||||
/// Symbol for the ExternalTextureParams struct
|
/// Symbol for the ExternalTextureParams struct
|
||||||
Symbol external_texture_params_struct_sym;
|
Symbol params_struct_sym;
|
||||||
|
|
||||||
/// Symbol for the textureLoadExternal function
|
/// Symbol for the textureLoadExternal function
|
||||||
Symbol texture_load_external_sym;
|
Symbol texture_load_external_sym;
|
||||||
|
@ -52,6 +64,337 @@ struct MultiplanarExternalTexture::State {
|
||||||
/// Storage for new bindings that have been created corresponding to an
|
/// Storage for new bindings that have been created corresponding to an
|
||||||
/// original texture_external binding.
|
/// original texture_external binding.
|
||||||
std::unordered_map<Symbol, NewBindingSymbols> new_binding_symbols;
|
std::unordered_map<Symbol, NewBindingSymbols> new_binding_symbols;
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// @param context the clone
|
||||||
|
/// @param newBindingPoints the input destination binding locations for the
|
||||||
|
/// expanded texture_external
|
||||||
|
State(CloneContext& context, const NewBindingPoints* newBindingPoints)
|
||||||
|
: ctx(context), b(*context.dst), new_binding_points(newBindingPoints) {}
|
||||||
|
|
||||||
|
/// Processes the module
|
||||||
|
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).
|
||||||
|
ctx.ReplaceAll([&](const ast::Variable* var) -> const ast::Variable* {
|
||||||
|
if (!::tint::Is<ast::ExternalTexture>(var->type)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the decorations are empty, then this must be a texture_external
|
||||||
|
// passed as a function parameter. These variables are transformed
|
||||||
|
// elsewhere.
|
||||||
|
if (var->decorations.empty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we find a texture_external binding, we know we must emit the
|
||||||
|
// ExternalTextureParams struct.
|
||||||
|
if (!params_struct_sym.IsValid()) {
|
||||||
|
createExtTexParamsStruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 = {var->BindingPoint().group->value,
|
||||||
|
var->BindingPoint().binding->value};
|
||||||
|
|
||||||
|
BindingsMap::const_iterator it =
|
||||||
|
new_binding_points->bindings_map.find(bp);
|
||||||
|
if (it == new_binding_points->bindings_map.end()) {
|
||||||
|
b.Diagnostics().add_error(
|
||||||
|
diag::System::Transform,
|
||||||
|
"missing new binding points for texture_external at binding {" +
|
||||||
|
std::to_string(bp.group) + "," + std::to_string(bp.binding) +
|
||||||
|
"}");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
// NewBindingSymbols new_binding_syms;
|
||||||
|
auto& syms = new_binding_symbols[var->symbol];
|
||||||
|
syms.plane_0 = ctx.Clone(var->symbol);
|
||||||
|
syms.plane_1 = b.Symbols().New("ext_tex_plane_1");
|
||||||
|
b.Global(syms.plane_1,
|
||||||
|
b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
|
||||||
|
b.GroupAndBinding(bps.plane_1.group, bps.plane_1.binding));
|
||||||
|
syms.params = b.Symbols().New("ext_tex_params");
|
||||||
|
b.Global(syms.params, b.ty.type_name("ExternalTextureParams"),
|
||||||
|
ast::StorageClass::kUniform,
|
||||||
|
b.GroupAndBinding(bps.params.group, bps.params.binding));
|
||||||
|
|
||||||
|
// Replace the original texture_external binding with a texture_2d<f32>
|
||||||
|
// binding.
|
||||||
|
ast::DecorationList cloned_decorations = ctx.Clone(var->decorations);
|
||||||
|
const ast::Expression* cloned_constructor = ctx.Clone(var->constructor);
|
||||||
|
|
||||||
|
return b.Var(syms.plane_0,
|
||||||
|
b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
|
||||||
|
cloned_constructor, cloned_decorations);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Transform the original textureLoad and textureSampleLevel calls into
|
||||||
|
// textureLoadExternal and textureSampleExternal calls.
|
||||||
|
ctx.ReplaceAll(
|
||||||
|
[&](const ast::CallExpression* expr) -> const ast::CallExpression* {
|
||||||
|
auto* intrinsic = sem.Get(expr)->Target()->As<sem::Intrinsic>();
|
||||||
|
|
||||||
|
if (intrinsic && !intrinsic->Parameters().empty() &&
|
||||||
|
intrinsic->Parameters()[0]->Type()->Is<sem::ExternalTexture>() &&
|
||||||
|
intrinsic->Type() != sem::IntrinsicType::kTextureDimensions) {
|
||||||
|
auto it = new_binding_symbols.find(
|
||||||
|
expr->args[0]->As<ast::IdentifierExpression>()->symbol);
|
||||||
|
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.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto& syms = it->second;
|
||||||
|
|
||||||
|
if (intrinsic->Type() == sem::IntrinsicType::kTextureLoad) {
|
||||||
|
return createTexLdExt(expr, syms);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intrinsic->Type() == sem::IntrinsicType::kTextureSampleLevel) {
|
||||||
|
return createTexSmpExt(expr, syms);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (sem.Get(expr)->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.
|
||||||
|
for (const ast::Expression* arg : expr->args) {
|
||||||
|
if (auto* id_expr = arg->As<ast::IdentifierExpression>()) {
|
||||||
|
// Check if a parameter is a texture_external by trying to find
|
||||||
|
// it in the transform state.
|
||||||
|
auto it = new_binding_symbols.find(id_expr->symbol);
|
||||||
|
if (it != new_binding_symbols.end()) {
|
||||||
|
auto& syms = it->second;
|
||||||
|
// When we find a texture_external, we must unpack it into its
|
||||||
|
// components.
|
||||||
|
ctx.Replace(id_expr, b.Expr(syms.plane_0));
|
||||||
|
ctx.InsertAfter(expr->args, id_expr, b.Expr(syms.plane_1));
|
||||||
|
ctx.InsertAfter(expr->args, id_expr, b.Expr(syms.params));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
});
|
||||||
|
|
||||||
|
// We must update all the texture_external parameters for user declared
|
||||||
|
// functions.
|
||||||
|
ctx.ReplaceAll([&](const ast::Function* fn) -> const ast::Function* {
|
||||||
|
for (const ast::Variable* param : fn->params) {
|
||||||
|
if (::tint::Is<ast::ExternalTexture>(param->type)) {
|
||||||
|
// If we find a texture_external, we must ensure the
|
||||||
|
// ExternalTextureParams struct exists.
|
||||||
|
if (!params_struct_sym.IsValid()) {
|
||||||
|
createExtTexParamsStruct();
|
||||||
|
}
|
||||||
|
// 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[param->symbol];
|
||||||
|
syms.plane_0 = ctx.Clone(param->symbol);
|
||||||
|
syms.plane_1 = b.Symbols().New("ext_tex_plane_1");
|
||||||
|
syms.params = b.Symbols().New("ext_tex_params");
|
||||||
|
auto tex2d_f32 = [&] {
|
||||||
|
return b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32());
|
||||||
|
};
|
||||||
|
ctx.Replace(param, b.Param(syms.plane_0, tex2d_f32()));
|
||||||
|
ctx.InsertAfter(fn->params, param,
|
||||||
|
b.Param(syms.plane_1, tex2d_f32()));
|
||||||
|
ctx.InsertAfter(
|
||||||
|
fn->params, param,
|
||||||
|
b.Param(syms.params, b.ty.type_name(params_struct_sym)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Clone the function. This will use the Replace() and InsertAfter() calls
|
||||||
|
// above.
|
||||||
|
return nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates the ExternalTextureParams struct.
|
||||||
|
void createExtTexParamsStruct() {
|
||||||
|
ast::StructMemberList member_list = {
|
||||||
|
b.Member("numPlanes", b.ty.u32()), b.Member("vr", b.ty.f32()),
|
||||||
|
b.Member("ug", b.ty.f32()), b.Member("vg", b.ty.f32()),
|
||||||
|
b.Member("ub", b.ty.f32())};
|
||||||
|
|
||||||
|
params_struct_sym = b.Symbols().New("ExternalTextureParams");
|
||||||
|
|
||||||
|
b.Structure(params_struct_sym, member_list,
|
||||||
|
ast::DecorationList{b.StructBlock()});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a StatementList containing all the statements making up the
|
||||||
|
/// bodies of the textureSampleExternal and textureLoadExternal functions.
|
||||||
|
/// @param callType determines which function body to generate
|
||||||
|
/// @returns a statement list that makes of the body of the chosen function
|
||||||
|
ast::StatementList createTexFnExtStatementList(sem::IntrinsicType callType) {
|
||||||
|
using f32 = ProgramBuilder::f32;
|
||||||
|
const ast::CallExpression* single_plane_call;
|
||||||
|
const ast::CallExpression* plane_0_call;
|
||||||
|
const ast::CallExpression* plane_1_call;
|
||||||
|
if (callType == sem::IntrinsicType::kTextureSampleLevel) {
|
||||||
|
// textureSampleLevel(plane0, smp, coord.xy, 0.0);
|
||||||
|
single_plane_call =
|
||||||
|
b.Call("textureSampleLevel", "plane0", "smp", "coord", 0.0f);
|
||||||
|
// textureSampleLevel(plane0, smp, coord.xy, 0.0);
|
||||||
|
plane_0_call =
|
||||||
|
b.Call("textureSampleLevel", "plane0", "smp", "coord", 0.0f);
|
||||||
|
// textureSampleLevel(plane1, smp, coord.xy, 0.0);
|
||||||
|
plane_1_call =
|
||||||
|
b.Call("textureSampleLevel", "plane1", "smp", "coord", 0.0f);
|
||||||
|
} else if (callType == sem::IntrinsicType::kTextureLoad) {
|
||||||
|
// textureLoad(plane0, coords.xy, 0);
|
||||||
|
single_plane_call = b.Call("textureLoad", "plane0", "coord", 0);
|
||||||
|
// textureLoad(plane0, coords.xy, 0);
|
||||||
|
plane_0_call = b.Call("textureLoad", "plane0", "coord", 0);
|
||||||
|
// textureLoad(plane1, coords.xy, 0);
|
||||||
|
plane_1_call = b.Call("textureLoad", "plane1", "coord", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
// if (params.numPlanes == 1u) {
|
||||||
|
// return singlePlaneCall
|
||||||
|
// }
|
||||||
|
b.If(b.create<ast::BinaryExpression>(
|
||||||
|
ast::BinaryOp::kEqual, b.MemberAccessor("params", "numPlanes"),
|
||||||
|
b.Expr(1u)),
|
||||||
|
b.Block(b.Return(single_plane_call))),
|
||||||
|
// let y = plane0Call.r - 0.0625;
|
||||||
|
b.Decl(b.Const("y", nullptr,
|
||||||
|
b.Sub(b.MemberAccessor(plane_0_call, "r"), 0.0625f))),
|
||||||
|
// let uv = plane1Call.rg - 0.5;
|
||||||
|
b.Decl(b.Const("uv", nullptr,
|
||||||
|
b.Sub(b.MemberAccessor(plane_1_call, "rg"), 0.5f))),
|
||||||
|
// let u = uv.x;
|
||||||
|
b.Decl(b.Const("u", nullptr, b.MemberAccessor("uv", "x"))),
|
||||||
|
// let v = uv.y;
|
||||||
|
b.Decl(b.Const("v", nullptr, b.MemberAccessor("uv", "y"))),
|
||||||
|
// let r = 1.164 * y + params.vr * v;
|
||||||
|
b.Decl(b.Const("r", nullptr,
|
||||||
|
b.Add(b.Mul(1.164f, "y"),
|
||||||
|
b.Mul(b.MemberAccessor("params", "vr"), "v")))),
|
||||||
|
// let g = 1.164 * y - params.ug * u - params.vg * v;
|
||||||
|
b.Decl(
|
||||||
|
b.Const("g", nullptr,
|
||||||
|
b.Sub(b.Sub(b.Mul(1.164f, "y"),
|
||||||
|
b.Mul(b.MemberAccessor("params", "ug"), "u")),
|
||||||
|
b.Mul(b.MemberAccessor("params", "vg"), "v")))),
|
||||||
|
// let b = 1.164 * y + params.ub * u;
|
||||||
|
b.Decl(b.Const("b", nullptr,
|
||||||
|
b.Add(b.Mul(1.164f, "y"),
|
||||||
|
b.Mul(b.MemberAccessor("params", "ub"), "u")))),
|
||||||
|
// return vec4<f32>(r, g, b, 1.0);
|
||||||
|
b.Return(b.vec4<f32>("r", "g", "b", 1.0f)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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* createTexSmpExt(const ast::CallExpression* expr,
|
||||||
|
NewBindingSymbols syms) {
|
||||||
|
ast::ExpressionList params;
|
||||||
|
const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
|
||||||
|
|
||||||
|
if (expr->args.size() != 3) {
|
||||||
|
TINT_ICE(Transform, b.Diagnostics())
|
||||||
|
<< "expected textureSampleLevel call with a "
|
||||||
|
"texture_external to have 3 parameters, found "
|
||||||
|
<< expr->args.size() << " parameters";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!texture_sample_external_sym.IsValid()) {
|
||||||
|
texture_sample_external_sym = b.Symbols().New("textureSampleExternal");
|
||||||
|
|
||||||
|
// Emit the textureSampleExternal function.
|
||||||
|
ast::VariableList varList = {
|
||||||
|
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))};
|
||||||
|
|
||||||
|
ast::StatementList statementList =
|
||||||
|
createTexFnExtStatementList(sem::IntrinsicType::kTextureSampleLevel);
|
||||||
|
|
||||||
|
b.Func(texture_sample_external_sym, varList, b.ty.vec4(b.ty.f32()),
|
||||||
|
statementList, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
const ast::IdentifierExpression* exp = b.Expr(texture_sample_external_sym);
|
||||||
|
params = {plane_0_binding_param, b.Expr(syms.plane_1),
|
||||||
|
ctx.Clone(expr->args[1]), ctx.Clone(expr->args[2]),
|
||||||
|
b.Expr(syms.params)};
|
||||||
|
return b.Call(exp, 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) {
|
||||||
|
ast::ExpressionList params;
|
||||||
|
const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
|
||||||
|
|
||||||
|
if (expr->args.size() != 2) {
|
||||||
|
TINT_ICE(Transform, b.Diagnostics())
|
||||||
|
<< "expected textureLoad call with a texture_external "
|
||||||
|
"to have 2 parameters, found "
|
||||||
|
<< expr->args.size() << " parameters";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!texture_load_external_sym.IsValid()) {
|
||||||
|
texture_load_external_sym = b.Symbols().New("textureLoadExternal");
|
||||||
|
|
||||||
|
// Emit the textureLoadExternal function.
|
||||||
|
ast::VariableList var_list = {
|
||||||
|
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("coord", b.ty.vec2(b.ty.i32())),
|
||||||
|
b.Param("params", b.ty.type_name(params_struct_sym))};
|
||||||
|
|
||||||
|
ast::StatementList statement_list =
|
||||||
|
createTexFnExtStatementList(sem::IntrinsicType::kTextureLoad);
|
||||||
|
|
||||||
|
b.Func(texture_load_external_sym, var_list, b.ty.vec4(b.ty.f32()),
|
||||||
|
statement_list, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
const ast::IdentifierExpression* exp = b.Expr(texture_load_external_sym);
|
||||||
|
params = {plane_0_binding_param, b.Expr(syms.plane_1),
|
||||||
|
ctx.Clone(expr->args[1]), b.Expr(syms.params)};
|
||||||
|
return b.Call(exp, params);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
MultiplanarExternalTexture::NewBindingPoints::NewBindingPoints(
|
MultiplanarExternalTexture::NewBindingPoints::NewBindingPoints(
|
||||||
|
@ -72,285 +415,21 @@ MultiplanarExternalTexture::~MultiplanarExternalTexture() = default;
|
||||||
void MultiplanarExternalTexture::Run(CloneContext& ctx,
|
void MultiplanarExternalTexture::Run(CloneContext& ctx,
|
||||||
const DataMap& inputs,
|
const DataMap& inputs,
|
||||||
DataMap&) {
|
DataMap&) {
|
||||||
State state;
|
|
||||||
auto& b = *ctx.dst;
|
|
||||||
|
|
||||||
auto* new_binding_points = inputs.Get<NewBindingPoints>();
|
auto* new_binding_points = inputs.Get<NewBindingPoints>();
|
||||||
|
|
||||||
if (!new_binding_points) {
|
if (!new_binding_points) {
|
||||||
b.Diagnostics().add_error(
|
ctx.dst->Diagnostics().add_error(
|
||||||
diag::System::Transform,
|
diag::System::Transform,
|
||||||
"missing new binding point data for " + std::string(TypeInfo().name));
|
"missing new binding point data for " + std::string(TypeInfo().name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& sem = ctx.src->Sem();
|
State state(ctx, new_binding_points);
|
||||||
|
|
||||||
// For each texture_external binding, we replace it with a texture_2d<f32>
|
state.Process();
|
||||||
// binding and create two additional bindings (one texture_2d<f32> to
|
|
||||||
// represent the secondary plane and one uniform buffer for the
|
|
||||||
// ExternalTextureParams struct).
|
|
||||||
ctx.ReplaceAll([&](const ast::Variable* var) -> const ast::Variable* {
|
|
||||||
if (!::tint::Is<ast::ExternalTexture>(var->type)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the decorations are empty, then this must be a texture_external being
|
|
||||||
// passed as a function parameter. We need to unpack this into multiple
|
|
||||||
// parameters - but this hasn't been implemented so produce an error.
|
|
||||||
if (var->decorations.empty()) {
|
|
||||||
b.Diagnostics().add_error(
|
|
||||||
diag::System::Transform,
|
|
||||||
"transforming a texture_external passed as a user-defined function "
|
|
||||||
"parameter has not been implemented.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we find a texture_external binding, we know we must emit the
|
|
||||||
// ExternalTextureParams struct.
|
|
||||||
if (!state.external_texture_params_struct_sym.IsValid()) {
|
|
||||||
ast::StructMemberList member_list = {
|
|
||||||
b.Member("numPlanes", b.ty.u32()), b.Member("vr", b.ty.f32()),
|
|
||||||
b.Member("ug", b.ty.f32()), b.Member("vg", b.ty.f32()),
|
|
||||||
b.Member("ub", b.ty.f32())};
|
|
||||||
|
|
||||||
state.external_texture_params_struct_sym =
|
|
||||||
b.Symbols().New("ExternalTextureParams");
|
|
||||||
|
|
||||||
b.Structure(state.external_texture_params_struct_sym, member_list,
|
|
||||||
ast::DecorationList{b.StructBlock()});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 = {var->BindingPoint().group->value,
|
|
||||||
var->BindingPoint().binding->value};
|
|
||||||
BindingPoints bps;
|
|
||||||
BindingsMap::const_iterator it = new_binding_points->bindings_map.find(bp);
|
|
||||||
if (it == new_binding_points->bindings_map.end()) {
|
|
||||||
b.Diagnostics().add_error(
|
|
||||||
diag::System::Transform,
|
|
||||||
"missing new binding points for texture_external at binding {" +
|
|
||||||
std::to_string(bp.group) + "," + std::to_string(bp.binding) +
|
|
||||||
"}");
|
|
||||||
return nullptr;
|
|
||||||
} else {
|
|
||||||
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 symbol associated with the texture_external binding that
|
|
||||||
// corresponds with the new bindings.
|
|
||||||
NewBindingSymbols new_binding_syms;
|
|
||||||
new_binding_syms.ext_tex_plane_1_binding_sym =
|
|
||||||
b.Symbols().New("ext_tex_plane_1");
|
|
||||||
b.Global(new_binding_syms.ext_tex_plane_1_binding_sym,
|
|
||||||
b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
|
|
||||||
b.GroupAndBinding(bps.plane_1.group, bps.plane_1.binding));
|
|
||||||
|
|
||||||
new_binding_syms.ext_tex_params_binding_sym =
|
|
||||||
b.Symbols().New("ext_tex_params");
|
|
||||||
b.Global(new_binding_syms.ext_tex_params_binding_sym,
|
|
||||||
b.ty.type_name("ExternalTextureParams"),
|
|
||||||
ast::StorageClass::kUniform,
|
|
||||||
b.GroupAndBinding(bps.params.group, bps.params.binding));
|
|
||||||
|
|
||||||
// Replace the original texture_external binding with a texture_2d<f32>
|
|
||||||
// binding.
|
|
||||||
auto cloned_sym = ctx.Clone(var->symbol);
|
|
||||||
ast::DecorationList cloned_decorations = ctx.Clone(var->decorations);
|
|
||||||
const ast::Expression* cloned_constructor = ctx.Clone(var->constructor);
|
|
||||||
state.new_binding_symbols[cloned_sym] = new_binding_syms;
|
|
||||||
|
|
||||||
return b.Var(cloned_sym,
|
|
||||||
b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
|
|
||||||
cloned_constructor, cloned_decorations);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Transform the original textureLoad and textureSampleLevel calls into
|
|
||||||
// textureLoadExternal and textureSampleExternal calls.
|
|
||||||
ctx.ReplaceAll([&](const ast::CallExpression* expr)
|
|
||||||
-> const ast::CallExpression* {
|
|
||||||
auto* intrinsic = sem.Get(expr)->Target()->As<sem::Intrinsic>();
|
|
||||||
|
|
||||||
if (!intrinsic ||
|
|
||||||
!intrinsic->Parameters()[0]->Type()->Is<sem::ExternalTexture>() ||
|
|
||||||
intrinsic->Parameters().empty() ||
|
|
||||||
intrinsic->Type() == sem::IntrinsicType::kTextureDimensions) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ast::Expression* ext_tex_plane_0_binding_param =
|
|
||||||
ctx.Clone(expr->args[0]);
|
|
||||||
|
|
||||||
// Lookup the symbols for the new bindings using the symbol from the
|
|
||||||
// original texture_external.
|
|
||||||
Symbol ext_tex_plane_1_binding_sym =
|
|
||||||
state
|
|
||||||
.new_binding_symbols[ext_tex_plane_0_binding_param
|
|
||||||
->As<ast::IdentifierExpression>()
|
|
||||||
->symbol]
|
|
||||||
.ext_tex_plane_1_binding_sym;
|
|
||||||
Symbol ext_tex_params_binding_sym =
|
|
||||||
state
|
|
||||||
.new_binding_symbols[ext_tex_plane_0_binding_param
|
|
||||||
->As<ast::IdentifierExpression>()
|
|
||||||
->symbol]
|
|
||||||
.ext_tex_params_binding_sym;
|
|
||||||
|
|
||||||
// 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 (!ext_tex_plane_1_binding_sym.IsValid() ||
|
|
||||||
!ext_tex_params_binding_sym.IsValid()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::IdentifierExpression* exp;
|
|
||||||
ast::ExpressionList params;
|
|
||||||
|
|
||||||
if (intrinsic->Type() == sem::IntrinsicType::kTextureLoad) {
|
|
||||||
if (expr->args.size() != 2) {
|
|
||||||
TINT_ICE(Transform, b.Diagnostics())
|
|
||||||
<< "expected textureLoad call with a texture_external "
|
|
||||||
"to "
|
|
||||||
"have 2 parameters, found "
|
|
||||||
<< expr->args.size() << " parameters";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!state.texture_load_external_sym.IsValid()) {
|
|
||||||
state.texture_load_external_sym =
|
|
||||||
b.Symbols().New("textureLoadExternal");
|
|
||||||
|
|
||||||
// Emit the textureLoadExternal function.
|
|
||||||
ast::VariableList var_list = {
|
|
||||||
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("coord", b.ty.vec2(b.ty.i32())),
|
|
||||||
b.Param("params",
|
|
||||||
b.ty.type_name(state.external_texture_params_struct_sym))};
|
|
||||||
|
|
||||||
ast::StatementList statement_list =
|
|
||||||
createTexFnExtStatementList(b, sem::IntrinsicType::kTextureLoad);
|
|
||||||
|
|
||||||
b.Func(state.texture_load_external_sym, var_list, b.ty.vec4(b.ty.f32()),
|
|
||||||
statement_list, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
exp =
|
|
||||||
b.create<ast::IdentifierExpression>(state.texture_load_external_sym);
|
|
||||||
params = {ext_tex_plane_0_binding_param,
|
|
||||||
b.Expr(ext_tex_plane_1_binding_sym), ctx.Clone(expr->args[1]),
|
|
||||||
b.Expr(ext_tex_params_binding_sym)};
|
|
||||||
} else if (intrinsic->Type() == sem::IntrinsicType::kTextureSampleLevel) {
|
|
||||||
if (expr->args.size() != 3) {
|
|
||||||
TINT_ICE(Transform, b.Diagnostics())
|
|
||||||
<< "expected textureSampleLevel call with a "
|
|
||||||
"texture_external to have 3 parameters, found "
|
|
||||||
<< expr->args.size() << " parameters";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!state.texture_sample_external_sym.IsValid()) {
|
|
||||||
state.texture_sample_external_sym =
|
|
||||||
b.Symbols().New("textureSampleExternal");
|
|
||||||
|
|
||||||
// Emit the textureSampleExternal function.
|
|
||||||
ast::VariableList varList = {
|
|
||||||
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(state.external_texture_params_struct_sym))};
|
|
||||||
|
|
||||||
ast::StatementList statementList = createTexFnExtStatementList(
|
|
||||||
b, sem::IntrinsicType::kTextureSampleLevel);
|
|
||||||
|
|
||||||
b.Func(state.texture_sample_external_sym, varList,
|
|
||||||
b.ty.vec4(b.ty.f32()), statementList, {});
|
|
||||||
}
|
|
||||||
exp = b.create<ast::IdentifierExpression>(
|
|
||||||
state.texture_sample_external_sym);
|
|
||||||
params = {ext_tex_plane_0_binding_param,
|
|
||||||
b.Expr(ext_tex_plane_1_binding_sym), ctx.Clone(expr->args[1]),
|
|
||||||
ctx.Clone(expr->args[2]), b.Expr(ext_tex_params_binding_sym)};
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.Call(exp, params);
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.Clone();
|
ctx.Clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructs a StatementList containing all the statements making up the bodies
|
|
||||||
// of the textureSampleExternal and textureLoadExternal functions.
|
|
||||||
ast::StatementList MultiplanarExternalTexture::createTexFnExtStatementList(
|
|
||||||
ProgramBuilder& b,
|
|
||||||
sem::IntrinsicType callType) {
|
|
||||||
using f32 = ProgramBuilder::f32;
|
|
||||||
const ast::CallExpression* single_plane_call;
|
|
||||||
const ast::CallExpression* plane_0_call;
|
|
||||||
const ast::CallExpression* plane_1_call;
|
|
||||||
if (callType == sem::IntrinsicType::kTextureSampleLevel) {
|
|
||||||
// textureSampleLevel(plane0, smp, coord.xy, 0.0);
|
|
||||||
single_plane_call =
|
|
||||||
b.Call("textureSampleLevel", "plane0", "smp", "coord", 0.0f);
|
|
||||||
// textureSampleLevel(plane0, smp, coord.xy, 0.0);
|
|
||||||
plane_0_call = b.Call("textureSampleLevel", "plane0", "smp", "coord", 0.0f);
|
|
||||||
// textureSampleLevel(plane1, smp, coord.xy, 0.0);
|
|
||||||
plane_1_call = b.Call("textureSampleLevel", "plane1", "smp", "coord", 0.0f);
|
|
||||||
} else if (callType == sem::IntrinsicType::kTextureLoad) {
|
|
||||||
// textureLoad(plane0, coords.xy, 0);
|
|
||||||
single_plane_call = b.Call("textureLoad", "plane0", "coord", 0);
|
|
||||||
// textureLoad(plane0, coords.xy, 0);
|
|
||||||
plane_0_call = b.Call("textureLoad", "plane0", "coord", 0);
|
|
||||||
// textureLoad(plane1, coords.xy, 0);
|
|
||||||
plane_1_call = b.Call("textureLoad", "plane1", "coord", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
// if (params.numPlanes == 1u) {
|
|
||||||
// return singlePlaneCall
|
|
||||||
// }
|
|
||||||
b.If(b.create<ast::BinaryExpression>(
|
|
||||||
ast::BinaryOp::kEqual, b.MemberAccessor("params", "numPlanes"),
|
|
||||||
b.Expr(1u)),
|
|
||||||
b.Block(b.Return(single_plane_call))),
|
|
||||||
// let y = plane0Call.r - 0.0625;
|
|
||||||
b.Decl(b.Const("y", nullptr,
|
|
||||||
b.Sub(b.MemberAccessor(plane_0_call, "r"), 0.0625f))),
|
|
||||||
// let uv = plane1Call.rg - 0.5;
|
|
||||||
b.Decl(b.Const("uv", nullptr,
|
|
||||||
b.Sub(b.MemberAccessor(plane_1_call, "rg"), 0.5f))),
|
|
||||||
// let u = uv.x;
|
|
||||||
b.Decl(b.Const("u", nullptr, b.MemberAccessor("uv", "x"))),
|
|
||||||
// let v = uv.y;
|
|
||||||
b.Decl(b.Const("v", nullptr, b.MemberAccessor("uv", "y"))),
|
|
||||||
// let r = 1.164 * y + params.vr * v;
|
|
||||||
b.Decl(b.Const("r", nullptr,
|
|
||||||
b.Add(b.Mul(1.164f, "y"),
|
|
||||||
b.Mul(b.MemberAccessor("params", "vr"), "v")))),
|
|
||||||
// let g = 1.164 * y - params.ug * u - params.vg * v;
|
|
||||||
b.Decl(b.Const("g", nullptr,
|
|
||||||
b.Sub(b.Sub(b.Mul(1.164f, "y"),
|
|
||||||
b.Mul(b.MemberAccessor("params", "ug"), "u")),
|
|
||||||
b.Mul(b.MemberAccessor("params", "vg"), "v")))),
|
|
||||||
// let b = 1.164 * y + params.ub * u;
|
|
||||||
b.Decl(b.Const("b", nullptr,
|
|
||||||
b.Add(b.Mul(1.164f, "y"),
|
|
||||||
b.Mul(b.MemberAccessor("params", "ub"), "u")))),
|
|
||||||
// return vec4<f32>(r, g, b, 1.0);
|
|
||||||
b.Return(b.vec4<f32>("r", "g", "b", 1.0f)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace transform
|
} // namespace transform
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -86,17 +86,6 @@ class MultiplanarExternalTexture
|
||||||
/// @param inputs optional extra transform-specific input data
|
/// @param inputs optional extra transform-specific input data
|
||||||
/// @param outputs optional extra transform-specific output data
|
/// @param outputs optional extra transform-specific output data
|
||||||
void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) override;
|
void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) override;
|
||||||
|
|
||||||
/// Creates the statement list for the TextureSampleExternal and
|
|
||||||
/// TextureLoadExternal functions.
|
|
||||||
/// @param b a reference to the ProgramBuilder associated with the destination
|
|
||||||
/// context
|
|
||||||
/// @param callType determines the kind of param list to emit (either
|
|
||||||
/// textureLoad or textureSampleLevel)
|
|
||||||
/// @returns a statement list that is used to create the TextureSampleExternal
|
|
||||||
/// and TextureLoadExternal functions.
|
|
||||||
ast::StatementList createTexFnExtStatementList(ProgramBuilder& b,
|
|
||||||
sem::IntrinsicType callType);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace transform
|
} // namespace transform
|
||||||
|
|
|
@ -379,21 +379,278 @@ fn main([[builtin(position)]] coord : vec4<f32>) -> [[location(0)]] vec4<f32> {
|
||||||
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParam) {
|
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParam) {
|
||||||
auto* src = R"(
|
auto* src = R"(
|
||||||
fn f(t : texture_external, s : sampler) {
|
fn f(t : texture_external, s : sampler) {
|
||||||
textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
|
textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[group(0), binding(0)]] var ext_tex : texture_external;
|
[[group(0), binding(0)]] var ext_tex : texture_external;
|
||||||
[[group(0), binding(1)]] var smp : sampler;
|
[[group(0), binding(1)]] var smp : sampler;
|
||||||
|
|
||||||
[[stage(fragment)]]
|
[[stage(fragment)]]
|
||||||
fn main() {
|
fn main() {
|
||||||
f(ext_tex, smp);
|
f(ext_tex, smp);
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
auto* expect =
|
auto* expect = R"(
|
||||||
"error: transforming a texture_external passed as a user-defined "
|
[[block]]
|
||||||
"function parameter has not been implemented.";
|
struct ExternalTextureParams {
|
||||||
|
numPlanes : u32;
|
||||||
|
vr : f32;
|
||||||
|
ug : f32;
|
||||||
|
vg : f32;
|
||||||
|
ub : f32;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
|
||||||
|
if ((params.numPlanes == 1u)) {
|
||||||
|
return textureSampleLevel(plane0, smp, coord, 0.0);
|
||||||
|
}
|
||||||
|
let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
|
||||||
|
let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
|
||||||
|
let u = uv.x;
|
||||||
|
let v = uv.y;
|
||||||
|
let r = ((1.164000034 * y) + (params.vr * v));
|
||||||
|
let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
|
||||||
|
let b = ((1.164000034 * y) + (params.ub * u));
|
||||||
|
return vec4<f32>(r, g, b, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(t : texture_2d<f32>, ext_tex_plane_1 : texture_2d<f32>, ext_tex_params : ExternalTextureParams, s : sampler) {
|
||||||
|
textureSampleExternal(t, ext_tex_plane_1, s, vec2<f32>(1.0, 2.0), ext_tex_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[group(0), binding(2)]] var ext_tex_plane_1_1 : texture_2d<f32>;
|
||||||
|
|
||||||
|
[[group(0), binding(3)]] var<uniform> ext_tex_params_1 : ExternalTextureParams;
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var ext_tex : texture_2d<f32>;
|
||||||
|
|
||||||
|
[[group(0), binding(1)]] var smp : sampler;
|
||||||
|
|
||||||
|
[[stage(fragment)]]
|
||||||
|
fn main() {
|
||||||
|
f(ext_tex, ext_tex_plane_1_1, ext_tex_params_1, 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 parameter not in the first
|
||||||
|
// position produces the correct output.
|
||||||
|
TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsSecondParam) {
|
||||||
|
auto* src = R"(
|
||||||
|
fn f(s : sampler, t : texture_external) {
|
||||||
|
textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var ext_tex : texture_external;
|
||||||
|
[[group(0), binding(1)]] var smp : sampler;
|
||||||
|
|
||||||
|
[[stage(fragment)]]
|
||||||
|
fn main() {
|
||||||
|
f(smp, ext_tex);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto* expect = R"(
|
||||||
|
[[block]]
|
||||||
|
struct ExternalTextureParams {
|
||||||
|
numPlanes : u32;
|
||||||
|
vr : f32;
|
||||||
|
ug : f32;
|
||||||
|
vg : f32;
|
||||||
|
ub : f32;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
|
||||||
|
if ((params.numPlanes == 1u)) {
|
||||||
|
return textureSampleLevel(plane0, smp, coord, 0.0);
|
||||||
|
}
|
||||||
|
let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
|
||||||
|
let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
|
||||||
|
let u = uv.x;
|
||||||
|
let v = uv.y;
|
||||||
|
let r = ((1.164000034 * y) + (params.vr * v));
|
||||||
|
let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
|
||||||
|
let b = ((1.164000034 * y) + (params.ub * u));
|
||||||
|
return vec4<f32>(r, g, b, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(s : sampler, t : texture_2d<f32>, ext_tex_plane_1 : texture_2d<f32>, ext_tex_params : ExternalTextureParams) {
|
||||||
|
textureSampleExternal(t, ext_tex_plane_1, s, vec2<f32>(1.0, 2.0), ext_tex_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[group(0), binding(2)]] var ext_tex_plane_1_1 : texture_2d<f32>;
|
||||||
|
|
||||||
|
[[group(0), binding(3)]] var<uniform> ext_tex_params_1 : ExternalTextureParams;
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var ext_tex : texture_2d<f32>;
|
||||||
|
|
||||||
|
[[group(0), binding(1)]] var smp : sampler;
|
||||||
|
|
||||||
|
[[stage(fragment)]]
|
||||||
|
fn main() {
|
||||||
|
f(smp, ext_tex, ext_tex_plane_1_1, ext_tex_params_1);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
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) {
|
||||||
|
textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
|
||||||
|
textureSampleLevel(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;
|
||||||
|
|
||||||
|
[[stage(fragment)]]
|
||||||
|
fn main() {
|
||||||
|
f(ext_tex, smp, ext_tex2);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto* expect = R"(
|
||||||
|
[[block]]
|
||||||
|
struct ExternalTextureParams {
|
||||||
|
numPlanes : u32;
|
||||||
|
vr : f32;
|
||||||
|
ug : f32;
|
||||||
|
vg : f32;
|
||||||
|
ub : f32;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
|
||||||
|
if ((params.numPlanes == 1u)) {
|
||||||
|
return textureSampleLevel(plane0, smp, coord, 0.0);
|
||||||
|
}
|
||||||
|
let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
|
||||||
|
let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
|
||||||
|
let u = uv.x;
|
||||||
|
let v = uv.y;
|
||||||
|
let r = ((1.164000034 * y) + (params.vr * v));
|
||||||
|
let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
|
||||||
|
let b = ((1.164000034 * y) + (params.ub * u));
|
||||||
|
return vec4<f32>(r, g, b, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(t : texture_2d<f32>, ext_tex_plane_1 : texture_2d<f32>, ext_tex_params : ExternalTextureParams, s : sampler, t2 : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams) {
|
||||||
|
textureSampleExternal(t, ext_tex_plane_1, s, vec2<f32>(1.0, 2.0), ext_tex_params);
|
||||||
|
textureSampleExternal(t2, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[group(0), binding(3)]] var ext_tex_plane_1_2 : texture_2d<f32>;
|
||||||
|
|
||||||
|
[[group(0), binding(4)]] var<uniform> ext_tex_params_2 : ExternalTextureParams;
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var ext_tex : texture_2d<f32>;
|
||||||
|
|
||||||
|
[[group(0), binding(1)]] var smp : sampler;
|
||||||
|
|
||||||
|
[[group(0), binding(5)]] var ext_tex_plane_1_3 : texture_2d<f32>;
|
||||||
|
|
||||||
|
[[group(0), binding(6)]] var<uniform> ext_tex_params_3 : ExternalTextureParams;
|
||||||
|
|
||||||
|
[[group(0), binding(2)]] var ext_tex2 : texture_2d<f32>;
|
||||||
|
|
||||||
|
[[stage(fragment)]]
|
||||||
|
fn main() {
|
||||||
|
f(ext_tex, ext_tex_plane_1_2, ext_tex_params_2, smp, ext_tex2, ext_tex_plane_1_3, ext_tex_params_3);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
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) {
|
||||||
|
textureSampleLevel(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;
|
||||||
|
|
||||||
|
[[stage(fragment)]]
|
||||||
|
fn main() {
|
||||||
|
f(ext_tex, smp);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto* expect = R"(
|
||||||
|
[[block]]
|
||||||
|
struct ExternalTextureParams {
|
||||||
|
numPlanes : u32;
|
||||||
|
vr : f32;
|
||||||
|
ug : f32;
|
||||||
|
vg : f32;
|
||||||
|
ub : f32;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
|
||||||
|
if ((params.numPlanes == 1u)) {
|
||||||
|
return textureSampleLevel(plane0, smp, coord, 0.0);
|
||||||
|
}
|
||||||
|
let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
|
||||||
|
let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
|
||||||
|
let u = uv.x;
|
||||||
|
let v = uv.y;
|
||||||
|
let r = ((1.164000034 * y) + (params.vr * v));
|
||||||
|
let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
|
||||||
|
let b = ((1.164000034 * y) + (params.ub * u));
|
||||||
|
return vec4<f32>(r, g, b, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nested(t : texture_2d<f32>, ext_tex_plane_1 : texture_2d<f32>, ext_tex_params : ExternalTextureParams, s : sampler) {
|
||||||
|
textureSampleExternal(t, ext_tex_plane_1, s, vec2<f32>(1.0, 2.0), ext_tex_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
|
||||||
|
nested(t, ext_tex_plane_1_1, ext_tex_params_1, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[group(0), binding(2)]] var ext_tex_plane_1_2 : texture_2d<f32>;
|
||||||
|
|
||||||
|
[[group(0), binding(3)]] var<uniform> ext_tex_params_2 : ExternalTextureParams;
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var ext_tex : texture_2d<f32>;
|
||||||
|
|
||||||
|
[[group(0), binding(1)]] var smp : sampler;
|
||||||
|
|
||||||
|
[[stage(fragment)]]
|
||||||
|
fn main() {
|
||||||
|
f(ext_tex, ext_tex_plane_1_2, ext_tex_params_2, smp);
|
||||||
|
}
|
||||||
|
)";
|
||||||
DataMap data;
|
DataMap data;
|
||||||
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
|
data.Add<MultiplanarExternalTexture::NewBindingPoints>(
|
||||||
MultiplanarExternalTexture::BindingsMap{
|
MultiplanarExternalTexture::BindingsMap{
|
||||||
|
|
Loading…
Reference in New Issue