transform: Update MultiplanarExternalTexture to support OOO-decls

MultiplanarExternalTexture cannot deal with out-of-order declarations.
Re-work things so that it can.

Bug: tint:1266
Change-Id: Ie2c8237be4f6ddb91120cbeb25f3c186b572ba59
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/79768
Reviewed-by: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Ben Clayton 2022-02-09 23:55:51 +00:00
parent 8ec32a6ec9
commit 8bbdda7e89
2 changed files with 134 additions and 129 deletions

View File

@ -48,8 +48,8 @@ struct MultiplanarExternalTexture::State {
/// ProgramBuilder for the context
ProgramBuilder& b;
/// Desination binding locations for the expanded texture_external provided as
/// input into the transform.
/// Destination binding locations for the expanded texture_external provided
/// as input into the transform.
const NewBindingPoints* new_binding_points;
/// Symbol for the ExternalTextureParams struct
@ -63,7 +63,8 @@ struct MultiplanarExternalTexture::State {
/// Storage for new bindings that have been created corresponding to an
/// original texture_external binding.
std::unordered_map<Symbol, NewBindingSymbols> new_binding_symbols;
std::unordered_map<const sem::Variable*, NewBindingSymbols>
new_binding_symbols;
/// Constructor
/// @param context the clone
@ -80,16 +81,17 @@ struct MultiplanarExternalTexture::State {
// 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 (!sem.Get<sem::ExternalTexture>(var->type)) {
return nullptr;
for (auto* var : ctx.src->AST().GlobalVariables()) {
auto* sem_var = sem.Get(var);
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 (var->attributes.empty()) {
return nullptr;
continue;
}
// If we find a texture_external binding, we know we must emit the
@ -113,7 +115,7 @@ struct MultiplanarExternalTexture::State {
"missing new binding points for texture_external at binding {" +
std::to_string(bp.group) + "," + std::to_string(bp.binding) +
"}");
return nullptr;
continue;
}
BindingPoints bps = it->second;
@ -123,7 +125,7 @@ struct MultiplanarExternalTexture::State {
// 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];
auto& syms = new_binding_symbols[sem_var];
syms.plane_0 = ctx.Clone(var->symbol);
syms.plane_1 = b.Symbols().New("ext_tex_plane_1");
b.Global(syms.plane_1,
@ -139,69 +141,21 @@ struct MultiplanarExternalTexture::State {
ast::AttributeList cloned_attributes = ctx.Clone(var->attributes);
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_attributes);
});
// Transform the original textureLoad and textureSampleLevel calls into
// textureLoadExternal and textureSampleExternal calls.
ctx.ReplaceAll(
[&](const ast::CallExpression* expr) -> const ast::CallExpression* {
auto* builtin = sem.Get(expr)->Target()->As<sem::Builtin>();
if (builtin && !builtin->Parameters().empty() &&
builtin->Parameters()[0]->Type()->Is<sem::ExternalTexture>() &&
builtin->Type() != sem::BuiltinType::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 (builtin->Type() == sem::BuiltinType::kTextureLoad) {
return createTexLdExt(expr, syms);
}
if (builtin->Type() == sem::BuiltinType::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;
});
auto* replacement =
b.Var(syms.plane_0,
b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
cloned_constructor, cloned_attributes);
ctx.Replace(var, replacement);
}
// We must update all the texture_external parameters for user declared
// functions.
ctx.ReplaceAll([&](const ast::Function* fn) -> const ast::Function* {
for (auto* fn : ctx.src->AST().Functions()) {
for (const ast::Variable* param : fn->params) {
if (sem.Get<sem::ExternalTexture>(param->type)) {
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 (!params_struct_sym.IsValid()) {
@ -211,7 +165,7 @@ struct MultiplanarExternalTexture::State {
// 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];
auto& syms = new_binding_symbols[sem_var];
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");
@ -226,10 +180,61 @@ struct MultiplanarExternalTexture::State {
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;
});
}
// Transform the original textureLoad and textureSampleLevel calls into
// textureLoadExternal and textureSampleExternal calls.
ctx.ReplaceAll(
[&](const ast::CallExpression* expr) -> const ast::CallExpression* {
auto* builtin = sem.Get(expr)->Target()->As<sem::Builtin>();
if (builtin && !builtin->Parameters().empty() &&
builtin->Parameters()[0]->Type()->Is<sem::ExternalTexture>() &&
builtin->Type() != sem::BuiltinType::kTextureDimensions) {
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.
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);
}
}
} 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 (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
// it in the transform state.
auto it = new_binding_symbols.find(var_user->Variable());
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(arg, b.Expr(syms.plane_0));
ctx.InsertAfter(expr->args, arg, b.Expr(syms.plane_1));
ctx.InsertAfter(expr->args, arg, b.Expr(syms.params));
}
}
}
}
return nullptr;
});
}
/// Creates the ExternalTextureParams struct.

View File

@ -149,8 +149,6 @@ fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
)";
auto* expect = R"(
@group(0) @binding(0) var s : sampler;
struct ExternalTextureParams {
numPlanes : u32;
vr : f32;
@ -163,6 +161,8 @@ struct ExternalTextureParams {
@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 textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
@ -259,8 +259,6 @@ fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
)";
auto* expect = R"(
@group(0) @binding(0) var s : sampler;
struct ExternalTextureParams {
numPlanes : u32;
vr : f32;
@ -273,6 +271,8 @@ struct ExternalTextureParams {
@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 textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
@ -332,8 +332,6 @@ fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
)";
auto* expect = R"(
@group(0) @binding(0) var s : sampler;
struct ExternalTextureParams {
numPlanes : u32;
vr : f32;
@ -346,24 +344,26 @@ struct ExternalTextureParams {
@group(0) @binding(5) var<uniform> ext_tex_params : ExternalTextureParams;
@group(0) @binding(1) var ext_tex : texture_2d<f32>;
@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(2) var ext_tex_1 : texture_2d<f32>;
@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(0) @binding(3) var ext_tex_2 : texture_2d<f32>;
@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 textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
@ -424,6 +424,10 @@ struct ExternalTextureParams {
ub : f32;
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
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);
@ -438,21 +442,17 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
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);
fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
}
@group(0) @binding(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);
f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
}
)";
DataMap data;
@ -490,6 +490,10 @@ struct ExternalTextureParams {
ub : f32;
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
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);
@ -504,21 +508,17 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
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);
fn f(s : sampler, t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams) {
textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
}
@group(0) @binding(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);
f(smp, ext_tex, ext_tex_plane_1, ext_tex_params);
}
)";
DataMap data;
@ -558,6 +558,14 @@ struct ExternalTextureParams {
ub : f32;
}
@group(0) @binding(3) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(4) var<uniform> ext_tex_params : ExternalTextureParams;
@group(0) @binding(5) var ext_tex_plane_1_1 : texture_2d<f32>;
@group(0) @binding(6) var<uniform> ext_tex_params_1 : ExternalTextureParams;
fn 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);
@ -572,28 +580,20 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
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);
fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler, t2 : texture_2d<f32>, ext_tex_plane_1_3 : texture_2d<f32>, ext_tex_params_3 : ExternalTextureParams) {
textureSampleExternal(t, ext_tex_plane_1_2, s, vec2<f32>(1.0, 2.0), ext_tex_params_2);
textureSampleExternal(t2, ext_tex_plane_1_3, s, vec2<f32>(1.0, 2.0), ext_tex_params_3);
}
@group(0) @binding(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);
f(ext_tex, ext_tex_plane_1, ext_tex_params, smp, ext_tex2, ext_tex_plane_1_1, ext_tex_params_1);
}
)";
DataMap data;
@ -636,6 +636,10 @@ struct ExternalTextureParams {
ub : f32;
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
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);
@ -650,25 +654,21 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
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 nested(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
}
fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
nested(t, ext_tex_plane_1_1, ext_tex_params_1, s);
fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler) {
nested(t, ext_tex_plane_1_2, ext_tex_params_2, s);
}
@group(0) @binding(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);
f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
}
)";
DataMap data;
@ -730,8 +730,6 @@ fn main() {
)";
auto* expect = R"(
type ET = texture_external;
struct ExternalTextureParams {
numPlanes : u32;
vr : f32;
@ -740,6 +738,12 @@ struct ExternalTextureParams {
ub : f32;
}
@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
type ET = texture_external;
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);
@ -754,21 +758,17 @@ fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp
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);
fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
}
@group(0) @binding(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);
f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
}
)";
DataMap data;