tint/transform/robustness: Implement predicated mode
This change overhauls the Robustness transform to support three modes, per address space: * ignore - Disable robustness checks for the address space * clamp - Clamp indices / texture args to ensure they're in bounds. This was the old behavior, and continues to be the default. * predicate - Condition all indexing / textureLoad / textureStore / atomic* operations on the bounds check. If any dependent value is out of bounds, then the operation is skipped. This change also fixes multiple expression evaluation of the texture builtin 'level' argument. Change-Id: I2e300ddff2c8d3183a9701f06985ce1b262baf2c Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/122343 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: James Price <jrprice@google.com> Kokoro: Ben Clayton <bclayton@chromium.org> Commit-Queue: Ben Clayton <bclayton@chromium.org>
This commit is contained in:
parent
5e56551551
commit
8525ff29da
|
@ -20,10 +20,15 @@
|
||||||
|
|
||||||
#include "src/tint/program_builder.h"
|
#include "src/tint/program_builder.h"
|
||||||
#include "src/tint/sem/block_statement.h"
|
#include "src/tint/sem/block_statement.h"
|
||||||
|
#include "src/tint/sem/builtin.h"
|
||||||
#include "src/tint/sem/call.h"
|
#include "src/tint/sem/call.h"
|
||||||
|
#include "src/tint/sem/function.h"
|
||||||
#include "src/tint/sem/index_accessor_expression.h"
|
#include "src/tint/sem/index_accessor_expression.h"
|
||||||
|
#include "src/tint/sem/load.h"
|
||||||
|
#include "src/tint/sem/member_accessor_expression.h"
|
||||||
#include "src/tint/sem/statement.h"
|
#include "src/tint/sem/statement.h"
|
||||||
#include "src/tint/sem/value_expression.h"
|
#include "src/tint/sem/value_expression.h"
|
||||||
|
#include "src/tint/transform/utils/hoist_to_decl_before.h"
|
||||||
#include "src/tint/type/reference.h"
|
#include "src/tint/type/reference.h"
|
||||||
|
|
||||||
TINT_INSTANTIATE_TYPEINFO(tint::transform::Robustness);
|
TINT_INSTANTIATE_TYPEINFO(tint::transform::Robustness);
|
||||||
|
@ -36,16 +41,147 @@ namespace tint::transform {
|
||||||
/// PIMPL state for the transform
|
/// PIMPL state for the transform
|
||||||
struct Robustness::State {
|
struct Robustness::State {
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param program the source program
|
/// @param p the source program
|
||||||
/// @param omitted the omitted address spaces
|
/// @param c the transform config
|
||||||
State(const Program* program, std::unordered_set<builtin::AddressSpace>&& omitted)
|
State(const Program* p, Config&& c) : src(p), cfg(std::move(c)) {}
|
||||||
: src(program), omitted_address_spaces(std::move(omitted)) {}
|
|
||||||
|
|
||||||
/// Runs the transform
|
/// Runs the transform
|
||||||
/// @returns the new program or SkipTransform if the transform is not required
|
/// @returns the new program or SkipTransform if the transform is not required
|
||||||
ApplyResult Run() {
|
ApplyResult Run() {
|
||||||
ctx.ReplaceAll([&](const ast::IndexAccessorExpression* expr) { return Transform(expr); });
|
if (HasAction(Action::kPredicate)) {
|
||||||
ctx.ReplaceAll([&](const ast::CallExpression* expr) { return Transform(expr); });
|
AddPredicateParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk all the AST nodes in the module, starting with the leaf nodes.
|
||||||
|
// The most deeply nested expressions will come first.
|
||||||
|
for (auto* node : ctx.src->ASTNodes().Objects()) {
|
||||||
|
Switch(
|
||||||
|
node, //
|
||||||
|
[&](const ast::IndexAccessorExpression* e) {
|
||||||
|
// obj[idx]
|
||||||
|
// Array, matrix and vector indexing may require robustness transformation.
|
||||||
|
auto* expr = sem.Get(e)->Unwrap()->As<sem::IndexAccessorExpression>();
|
||||||
|
switch (ActionFor(expr)) {
|
||||||
|
case Action::kPredicate:
|
||||||
|
PredicateIndexAccessor(expr);
|
||||||
|
break;
|
||||||
|
case Action::kClamp:
|
||||||
|
ClampIndexAccessor(expr);
|
||||||
|
break;
|
||||||
|
case Action::kIgnore:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const ast::IdentifierExpression* e) {
|
||||||
|
// Identifiers may resolve to pointer lets, which may be predicated.
|
||||||
|
// Inspect.
|
||||||
|
if (auto* user = sem.Get<sem::VariableUser>(e)) {
|
||||||
|
auto* v = user->Variable();
|
||||||
|
if (v->Type()->Is<type::Pointer>()) {
|
||||||
|
// Propagate predicate from pointer
|
||||||
|
if (auto pred = predicates.Get(v->Declaration()->initializer)) {
|
||||||
|
predicates.Add(e, *pred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const ast::AccessorExpression* e) {
|
||||||
|
// obj.member
|
||||||
|
// Propagate the predication from the object to this expression.
|
||||||
|
if (auto pred = predicates.Get(e->object)) {
|
||||||
|
predicates.Add(e, *pred);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const ast::UnaryOpExpression* e) {
|
||||||
|
// Includes address-of, or indirection
|
||||||
|
// Propagate the predication from the inner expression to this expression.
|
||||||
|
if (auto pred = predicates.Get(e->expr)) {
|
||||||
|
predicates.Add(e, *pred);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const ast::AssignmentStatement* s) {
|
||||||
|
if (auto pred = predicates.Get(s->lhs)) {
|
||||||
|
// Assignment target is predicated
|
||||||
|
// Replace statement with condition on the predicate
|
||||||
|
ctx.Replace(s, b.If(*pred, b.Block(ctx.Clone(s))));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const ast::CompoundAssignmentStatement* s) {
|
||||||
|
if (auto pred = predicates.Get(s->lhs)) {
|
||||||
|
// Assignment expression is predicated
|
||||||
|
// Replace statement with condition on the predicate
|
||||||
|
ctx.Replace(s, b.If(*pred, b.Block(ctx.Clone(s))));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const ast::IncrementDecrementStatement* s) {
|
||||||
|
if (auto pred = predicates.Get(s->lhs)) {
|
||||||
|
// Assignment expression is predicated
|
||||||
|
// Replace statement with condition on the predicate
|
||||||
|
ctx.Replace(s, b.If(*pred, b.Block(ctx.Clone(s))));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const ast::CallExpression* e) {
|
||||||
|
if (auto* call = sem.Get<sem::Call>(e)) {
|
||||||
|
Switch(
|
||||||
|
call->Target(), //
|
||||||
|
[&](const sem::Builtin* builtin) {
|
||||||
|
// Calls to builtins may require robustness transformation.
|
||||||
|
// Inspect.
|
||||||
|
if (builtin->IsTexture()) {
|
||||||
|
switch (cfg.texture_action) {
|
||||||
|
case Action::kPredicate:
|
||||||
|
PredicateTextureBuiltin(call, builtin);
|
||||||
|
break;
|
||||||
|
case Action::kClamp:
|
||||||
|
ClampTextureBuiltin(call, builtin);
|
||||||
|
break;
|
||||||
|
case Action::kIgnore:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MaybePredicateNonTextureBuiltin(call, builtin);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const sem::Function* fn) {
|
||||||
|
// Calls to user function may require passing additional predicate
|
||||||
|
// arguments.
|
||||||
|
InsertPredicateArguments(call, fn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check whether the node is an expression that:
|
||||||
|
// * Has a predicate
|
||||||
|
// * Is of a non-pointer or non-reference type
|
||||||
|
// If the above is true, then we need to predicate evaluation of this expression by
|
||||||
|
// replacing `expr` with `predicated_expr` and injecting the following above the
|
||||||
|
// expression's statement:
|
||||||
|
//
|
||||||
|
// var predicated_expr : expr_ty;
|
||||||
|
// if (predicate) {
|
||||||
|
// predicated_expr = expr;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
if (auto* expr = node->As<ast::Expression>()) {
|
||||||
|
if (auto pred = predicates.Get(expr)) {
|
||||||
|
// Expression is predicated
|
||||||
|
auto* sem_expr = sem.GetVal(expr);
|
||||||
|
if (!sem_expr->Type()->IsAnyOf<type::Reference, type::Pointer>()) {
|
||||||
|
auto pred_load = b.Symbols().New("predicated_expr");
|
||||||
|
auto ty = CreateASTTypeFor(ctx, sem_expr->Type());
|
||||||
|
hoist.InsertBefore(sem_expr->Stmt(), b.Decl(b.Var(pred_load, ty)));
|
||||||
|
hoist.InsertBefore(
|
||||||
|
sem_expr->Stmt(),
|
||||||
|
b.If(*pred, b.Block(b.Assign(pred_load, ctx.Clone(expr)))));
|
||||||
|
ctx.Replace(expr, b.Expr(pred_load));
|
||||||
|
|
||||||
|
// The predication has been consumed for this expression.
|
||||||
|
// Don't predicate expressions that use this expression.
|
||||||
|
predicates.Remove(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Clone();
|
ctx.Clone();
|
||||||
return Program(std::move(b));
|
return Program(std::move(b));
|
||||||
|
@ -54,227 +190,486 @@ struct Robustness::State {
|
||||||
private:
|
private:
|
||||||
/// The source program
|
/// The source program
|
||||||
const Program* const src;
|
const Program* const src;
|
||||||
|
/// The transform's config
|
||||||
|
Config cfg;
|
||||||
/// The target program builder
|
/// The target program builder
|
||||||
ProgramBuilder b;
|
ProgramBuilder b{};
|
||||||
/// The clone context
|
/// The clone context
|
||||||
CloneContext ctx = {&b, src, /* auto_clone_symbols */ true};
|
CloneContext ctx = {&b, src, /* auto_clone_symbols */ true};
|
||||||
|
/// Helper for hoisting declarations
|
||||||
|
HoistToDeclBefore hoist{ctx};
|
||||||
|
/// Alias to the source program's semantic info
|
||||||
|
const sem::Info& sem = ctx.src->Sem();
|
||||||
|
/// Map of expression to predicate condition
|
||||||
|
utils::Hashmap<const ast::Expression*, Symbol, 32> predicates{};
|
||||||
|
|
||||||
/// Set of address spaces to not apply the transform to
|
/// @return the `u32` typed expression that represents the maximum indexable value for the index
|
||||||
std::unordered_set<builtin::AddressSpace> omitted_address_spaces;
|
/// accessor @p expr, or nullptr if there is no robustness limit for this expression.
|
||||||
|
const ast::Expression* DynamicLimitFor(const sem::IndexAccessorExpression* expr) {
|
||||||
/// Apply bounds clamping to array, vector and matrix indexing
|
auto* obj_type = expr->Object()->Type();
|
||||||
/// @param expr the array, vector or matrix index expression
|
return Switch(
|
||||||
/// @return the clamped replacement expression, or nullptr if `expr` should be cloned without
|
obj_type->UnwrapRef(), //
|
||||||
/// changes.
|
|
||||||
const ast::IndexAccessorExpression* Transform(const ast::IndexAccessorExpression* expr) {
|
|
||||||
auto* sem = src->Sem().Get(expr)->Unwrap()->As<sem::IndexAccessorExpression>();
|
|
||||||
auto* ret_type = sem->Type();
|
|
||||||
|
|
||||||
auto* ref = ret_type->As<type::Reference>();
|
|
||||||
if (ref && omitted_address_spaces.count(ref->AddressSpace()) != 0) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// idx return the cloned index expression, as a u32.
|
|
||||||
auto idx = [&]() -> const ast::Expression* {
|
|
||||||
auto* i = ctx.Clone(expr->index);
|
|
||||||
if (sem->Index()->Type()->is_signed_integer_scalar()) {
|
|
||||||
return b.Call<u32>(i); // u32(idx)
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto* clamped_idx = Switch(
|
|
||||||
sem->Object()->Type()->UnwrapRef(), //
|
|
||||||
[&](const type::Vector* vec) -> const ast::Expression* {
|
[&](const type::Vector* vec) -> const ast::Expression* {
|
||||||
if (sem->Index()->ConstantValue()) {
|
if (expr->Index()->ConstantValue() || expr->Index()->Is<sem::Swizzle>()) {
|
||||||
// Index and size is constant.
|
// Index and size is constant.
|
||||||
// Validation will have rejected any OOB accesses.
|
// Validation will have rejected any OOB accesses.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
return b.Expr(u32(vec->Width() - 1u));
|
||||||
return b.Call("min", idx(), u32(vec->Width() - 1u));
|
|
||||||
},
|
},
|
||||||
[&](const type::Matrix* mat) -> const ast::Expression* {
|
[&](const type::Matrix* mat) -> const ast::Expression* {
|
||||||
if (sem->Index()->ConstantValue()) {
|
if (expr->Index()->ConstantValue()) {
|
||||||
// Index and size is constant.
|
// Index and size is constant.
|
||||||
// Validation will have rejected any OOB accesses.
|
// Validation will have rejected any OOB accesses.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
return b.Expr(u32(mat->columns() - 1u));
|
||||||
return b.Call("min", idx(), u32(mat->columns() - 1u));
|
|
||||||
},
|
},
|
||||||
[&](const type::Array* arr) -> const ast::Expression* {
|
[&](const type::Array* arr) -> const ast::Expression* {
|
||||||
const ast::Expression* max = nullptr;
|
|
||||||
if (arr->Count()->Is<type::RuntimeArrayCount>()) {
|
if (arr->Count()->Is<type::RuntimeArrayCount>()) {
|
||||||
// Size is unknown until runtime.
|
// Size is unknown until runtime.
|
||||||
// Must clamp, even if the index is constant.
|
// Must clamp, even if the index is constant.
|
||||||
auto* arr_ptr = b.AddressOf(ctx.Clone(expr->object));
|
|
||||||
max = b.Sub(b.Call("arrayLength", arr_ptr), 1_u);
|
auto* arr_ptr = b.AddressOf(ctx.Clone(expr->Object()->Declaration()));
|
||||||
} else if (auto count = arr->ConstantCount()) {
|
return b.Sub(b.Call(sem::BuiltinType::kArrayLength, arr_ptr), 1_u);
|
||||||
if (sem->Index()->ConstantValue()) {
|
}
|
||||||
|
if (auto count = arr->ConstantCount()) {
|
||||||
|
if (expr->Index()->ConstantValue()) {
|
||||||
// Index and size is constant.
|
// Index and size is constant.
|
||||||
// Validation will have rejected any OOB accesses.
|
// Validation will have rejected any OOB accesses.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
max = b.Expr(u32(count.value() - 1u));
|
return b.Expr(u32(count.value() - 1u));
|
||||||
} else {
|
}
|
||||||
// Note: Don't be tempted to use the array override variable as an expression
|
// Note: Don't be tempted to use the array override variable as an expression here,
|
||||||
// here, the name might be shadowed!
|
// the name might be shadowed!
|
||||||
b.Diagnostics().add_error(diag::System::Transform,
|
b.Diagnostics().add_error(diag::System::Transform,
|
||||||
type::Array::kErrExpectedConstantCount);
|
type::Array::kErrExpectedConstantCount);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
return b.Call("min", idx(), max);
|
|
||||||
},
|
},
|
||||||
[&](Default) {
|
[&](Default) -> const ast::Expression* {
|
||||||
TINT_ICE(Transform, b.Diagnostics())
|
TINT_ICE(Transform, b.Diagnostics())
|
||||||
<< "unhandled object type in robustness of array index: "
|
<< "unhandled object type in robustness of array index: "
|
||||||
<< src->FriendlyName(ret_type->UnwrapRef());
|
<< src->FriendlyName(obj_type->UnwrapRef());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!clamped_idx) {
|
|
||||||
return nullptr; // Clamping not needed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto idx_src = ctx.Clone(expr->source);
|
/// Transform the program to insert additional predicate parameters to all user functions that
|
||||||
auto* idx_obj = ctx.Clone(expr->object);
|
/// have a pointer parameter type in an address space that has predicate action.
|
||||||
return b.IndexAccessor(idx_src, idx_obj, clamped_idx);
|
void AddPredicateParameters() {
|
||||||
|
for (auto* fn : src->AST().Functions()) {
|
||||||
|
for (auto* param : fn->params) {
|
||||||
|
auto* sem_param = sem.Get(param);
|
||||||
|
if (auto* ptr = sem_param->Type()->As<type::Pointer>()) {
|
||||||
|
if (ActionFor(ptr->AddressSpace()) == Action::kPredicate) {
|
||||||
|
auto name = b.Symbols().New(src->Symbols().NameFor(param->name->symbol) +
|
||||||
|
"_predicate");
|
||||||
|
ctx.InsertAfter(fn->params, param, b.Param(name, b.ty.bool_()));
|
||||||
|
|
||||||
|
// Associate the pointer parameter expressions with the predicate.
|
||||||
|
for (auto* user : sem_param->Users()) {
|
||||||
|
predicates.Add(user->Declaration(), name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param type builtin type
|
/// Transforms call expressions to user functions, inserting additional predicate arguments
|
||||||
/// @returns true if the given builtin is a texture function that requires
|
/// after all pointer parameters with a type in an address space that has predicate action.
|
||||||
/// argument clamping,
|
void InsertPredicateArguments(const sem::Call* call, const sem::Function* fn) {
|
||||||
bool TextureBuiltinNeedsClamping(sem::BuiltinType type) {
|
auto* expr = call->Declaration();
|
||||||
return type == sem::BuiltinType::kTextureLoad || type == sem::BuiltinType::kTextureStore;
|
for (size_t i = 0; i < fn->Parameters().Length(); i++) {
|
||||||
|
auto* param = fn->Parameters()[i];
|
||||||
|
if (auto* ptr = param->Type()->As<type::Pointer>()) {
|
||||||
|
if (ActionFor(ptr->AddressSpace()) == Action::kPredicate) {
|
||||||
|
auto* arg = expr->args[i];
|
||||||
|
if (auto predicate = predicates.Get(arg)) {
|
||||||
|
ctx.InsertAfter(expr->args, arg, b.Expr(*predicate));
|
||||||
|
} else {
|
||||||
|
ctx.InsertAfter(expr->args, arg, b.Expr(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply bounds clamping to the coordinates, array index and level arguments
|
/// Applies predication to the index on an array, vector or matrix.
|
||||||
/// of the `textureLoad()` and `textureStore()` builtins.
|
/// @param expr the index accessor expression.
|
||||||
/// @param expr the builtin call expression
|
void PredicateIndexAccessor(const sem::IndexAccessorExpression* expr) {
|
||||||
/// @return the clamped replacement call expression, or nullptr if `expr`
|
auto* obj = expr->Object()->Declaration();
|
||||||
/// should be cloned without changes.
|
auto* idx = expr->Index()->Declaration();
|
||||||
const ast::CallExpression* Transform(const ast::CallExpression* expr) {
|
auto* max = DynamicLimitFor(expr);
|
||||||
auto* call = src->Sem().Get(expr)->UnwrapMaterialize()->As<sem::Call>();
|
if (!max) {
|
||||||
auto* call_target = call->Target();
|
// robustness is not required
|
||||||
auto* builtin = call_target->As<sem::Builtin>();
|
// Just propagate predicate from object
|
||||||
if (!builtin || !TextureBuiltinNeedsClamping(builtin->Type())) {
|
if (auto pred = predicates.Get(obj)) {
|
||||||
return nullptr; // No transform, just clone.
|
predicates.Add(expr->Declaration(), *pred);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* stmt = expr->Stmt();
|
||||||
|
auto obj_pred = *predicates.GetOrZero(obj);
|
||||||
|
|
||||||
|
auto idx_let = b.Symbols().New("index");
|
||||||
|
auto pred = b.Symbols().New("predicate");
|
||||||
|
|
||||||
|
hoist.InsertBefore(stmt, b.Decl(b.Let(idx_let, ctx.Clone(idx))));
|
||||||
|
ctx.Replace(idx, b.Expr(idx_let));
|
||||||
|
|
||||||
|
auto* cond = b.LessThanEqual(b.Call<u32>(b.Expr(idx_let)), max);
|
||||||
|
if (obj_pred.IsValid()) {
|
||||||
|
cond = b.And(b.Expr(obj_pred), cond);
|
||||||
|
}
|
||||||
|
hoist.InsertBefore(stmt, b.Decl(b.Let(pred, cond)));
|
||||||
|
|
||||||
|
predicates.Add(expr->Declaration(), pred);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Applies bounds clamping to the index on an array, vector or matrix.
|
||||||
|
/// @param expr the index accessor expression.
|
||||||
|
void ClampIndexAccessor(const sem::IndexAccessorExpression* expr) {
|
||||||
|
auto* max = DynamicLimitFor(expr);
|
||||||
|
if (!max) {
|
||||||
|
return; // robustness is not required
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* expr_sem = expr->Unwrap()->As<sem::IndexAccessorExpression>();
|
||||||
|
|
||||||
|
auto idx = ctx.Clone(expr->Declaration()->index);
|
||||||
|
if (expr_sem->Index()->Type()->is_signed_integer_scalar()) {
|
||||||
|
idx = b.Call<u32>(idx); // u32(idx)
|
||||||
|
}
|
||||||
|
auto* clamped_idx = b.Call(sem::BuiltinType::kMin, idx, max);
|
||||||
|
ctx.Replace(expr->Declaration()->index, clamped_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Applies predication to the non-texture builtin call, if required.
|
||||||
|
void MaybePredicateNonTextureBuiltin(const sem::Call* call, const sem::Builtin* builtin) {
|
||||||
|
// Gather the predications for the builtin arguments
|
||||||
|
const ast::Expression* predicate = nullptr;
|
||||||
|
for (auto* arg : call->Declaration()->args) {
|
||||||
|
if (auto pred = predicates.Get(arg)) {
|
||||||
|
predicate = And(predicate, b.Expr(*pred));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (predicate) {
|
||||||
|
if (builtin->Type() == sem::BuiltinType::kWorkgroupUniformLoad) {
|
||||||
|
// https://www.w3.org/TR/WGSL/#workgroupUniformLoad-builtin:
|
||||||
|
// "Executes a control barrier synchronization function that affects memory and
|
||||||
|
// atomic operations in the workgroup address space."
|
||||||
|
// Because the call acts like a control barrier, we need to make sure that we still
|
||||||
|
// trigger a workgroup barrier if the predicate fails.
|
||||||
|
PredicateCall(call, predicate,
|
||||||
|
b.Block(b.CallStmt(b.Call(sem::BuiltinType::kWorkgroupBarrier))));
|
||||||
|
} else {
|
||||||
|
PredicateCall(call, predicate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Applies predication to texture builtins, based on whether the coordinates, array index and
|
||||||
|
/// level arguments are all in bounds.
|
||||||
|
void PredicateTextureBuiltin(const sem::Call* call, const sem::Builtin* builtin) {
|
||||||
|
if (!TextureBuiltinNeedsRobustness(builtin->Type())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* expr = call->Declaration();
|
||||||
|
auto* stmt = call->Stmt();
|
||||||
|
|
||||||
// Indices of the mandatory texture and coords parameters, and the optional
|
// Indices of the mandatory texture and coords parameters, and the optional
|
||||||
// array and level parameters.
|
// array and level parameters.
|
||||||
auto& signature = builtin->Signature();
|
auto& signature = builtin->Signature();
|
||||||
auto texture_idx = signature.IndexOf(sem::ParameterUsage::kTexture);
|
auto texture_arg_idx = signature.IndexOf(sem::ParameterUsage::kTexture);
|
||||||
auto coords_idx = signature.IndexOf(sem::ParameterUsage::kCoords);
|
auto coords_arg_idx = signature.IndexOf(sem::ParameterUsage::kCoords);
|
||||||
auto array_idx = signature.IndexOf(sem::ParameterUsage::kArrayIndex);
|
auto array_arg_idx = signature.IndexOf(sem::ParameterUsage::kArrayIndex);
|
||||||
auto level_idx = signature.IndexOf(sem::ParameterUsage::kLevel);
|
auto level_arg_idx = signature.IndexOf(sem::ParameterUsage::kLevel);
|
||||||
|
|
||||||
auto* texture_arg = expr->args[static_cast<size_t>(texture_idx)];
|
auto* texture_arg = expr->args[static_cast<size_t>(texture_arg_idx)];
|
||||||
auto* coords_arg = expr->args[static_cast<size_t>(coords_idx)];
|
|
||||||
auto* coords_ty = builtin->Parameters()[static_cast<size_t>(coords_idx)]->Type();
|
|
||||||
|
|
||||||
auto width_of = [&](const type::Type* ty) {
|
// Build the builtin predicate from the arguments
|
||||||
if (auto* vec = ty->As<type::Vector>()) {
|
const ast::Expression* predicate = nullptr;
|
||||||
return vec->Width();
|
|
||||||
|
Symbol level_idx, num_levels;
|
||||||
|
if (level_arg_idx >= 0) {
|
||||||
|
auto* param = builtin->Parameters()[static_cast<size_t>(level_arg_idx)];
|
||||||
|
if (param->Type()->is_integer_scalar()) {
|
||||||
|
// let level_idx = u32(level-arg);
|
||||||
|
level_idx = b.Symbols().New("level_idx");
|
||||||
|
auto* arg = expr->args[static_cast<size_t>(level_arg_idx)];
|
||||||
|
hoist.InsertBefore(stmt,
|
||||||
|
b.Decl(b.Let(level_idx, CastToUnsigned(ctx.Clone(arg), 1u))));
|
||||||
|
|
||||||
|
// let num_levels = textureNumLevels(texture-arg);
|
||||||
|
num_levels = b.Symbols().New("num_levels");
|
||||||
|
hoist.InsertBefore(
|
||||||
|
stmt, b.Decl(b.Let(num_levels, b.Call(sem::BuiltinType::kTextureNumLevels,
|
||||||
|
ctx.Clone(texture_arg)))));
|
||||||
|
|
||||||
|
// predicate: level_idx < num_levels
|
||||||
|
predicate = And(predicate, b.LessThan(level_idx, num_levels));
|
||||||
|
|
||||||
|
// Replace the level argument with `level_idx`
|
||||||
|
ctx.Replace(arg, b.Expr(level_idx));
|
||||||
}
|
}
|
||||||
return 1u;
|
|
||||||
};
|
|
||||||
auto scalar_or_vec_ty = [&](ast::Type scalar, uint32_t width) {
|
|
||||||
if (width > 1) {
|
|
||||||
return b.ty.vec(scalar, width);
|
|
||||||
}
|
}
|
||||||
return scalar;
|
|
||||||
};
|
Symbol coords;
|
||||||
auto scalar_or_vec = [&](const ast::Expression* scalar,
|
if (coords_arg_idx >= 0) {
|
||||||
uint32_t width) -> const ast::Expression* {
|
auto* param = builtin->Parameters()[static_cast<size_t>(coords_arg_idx)];
|
||||||
if (width > 1) {
|
if (param->Type()->is_integer_scalar_or_vector()) {
|
||||||
return b.Call(b.ty.vec<Infer>(width), scalar);
|
// let coords = u32(coords-arg)
|
||||||
|
coords = b.Symbols().New("coords");
|
||||||
|
auto* arg = expr->args[static_cast<size_t>(coords_arg_idx)];
|
||||||
|
hoist.InsertBefore(stmt,
|
||||||
|
b.Decl(b.Let(coords, CastToUnsigned(b.Expr(ctx.Clone(arg)),
|
||||||
|
WidthOf(param->Type())))));
|
||||||
|
|
||||||
|
// predicate: all(coords < textureDimensions(texture))
|
||||||
|
auto* dimensions =
|
||||||
|
level_idx.IsValid()
|
||||||
|
? b.Call(sem::BuiltinType::kTextureDimensions, ctx.Clone(texture_arg),
|
||||||
|
b.Call(sem::BuiltinType::kMin, b.Expr(level_idx),
|
||||||
|
b.Sub(num_levels, 1_a)))
|
||||||
|
: b.Call(sem::BuiltinType::kTextureDimensions, ctx.Clone(texture_arg));
|
||||||
|
predicate =
|
||||||
|
And(predicate, b.Call(sem::BuiltinType::kAll, b.LessThan(coords, dimensions)));
|
||||||
|
|
||||||
|
// Replace the level argument with `coord`
|
||||||
|
ctx.Replace(arg, b.Expr(coords));
|
||||||
}
|
}
|
||||||
return scalar;
|
|
||||||
};
|
|
||||||
auto cast_to_signed = [&](const ast::Expression* val, uint32_t width) {
|
|
||||||
return b.Call(scalar_or_vec_ty(b.ty.i32(), width), val);
|
|
||||||
};
|
|
||||||
auto cast_to_unsigned = [&](const ast::Expression* val, uint32_t width) {
|
|
||||||
return b.Call(scalar_or_vec_ty(b.ty.u32(), width), val);
|
|
||||||
};
|
|
||||||
|
|
||||||
// If the level is provided, then we need to clamp this. As the level is
|
|
||||||
// used by textureDimensions() and the texture[Load|Store]() calls, we need
|
|
||||||
// to clamp both usages.
|
|
||||||
// TODO(bclayton): We probably want to place this into a let so that the
|
|
||||||
// calculation can be reused. This is fiddly to get right.
|
|
||||||
std::function<const ast::Expression*()> level_arg;
|
|
||||||
if (level_idx >= 0) {
|
|
||||||
level_arg = [&] {
|
|
||||||
const auto* arg = expr->args[static_cast<size_t>(level_idx)];
|
|
||||||
const auto* target_ty =
|
|
||||||
builtin->Parameters()[static_cast<size_t>(level_idx)]->Type();
|
|
||||||
const auto* num_levels = b.Call("textureNumLevels", ctx.Clone(texture_arg));
|
|
||||||
|
|
||||||
// TODO(crbug.com/tint/1526) remove when num_levels returns u32
|
|
||||||
num_levels = cast_to_unsigned(num_levels, 1u);
|
|
||||||
|
|
||||||
const auto* unsigned_max = b.Sub(num_levels, 1_a);
|
|
||||||
if (target_ty->is_signed_integer_scalar()) {
|
|
||||||
const auto* signed_max = cast_to_signed(unsigned_max, 1u);
|
|
||||||
return b.Call("clamp", ctx.Clone(arg), 0_a, signed_max);
|
|
||||||
} else {
|
|
||||||
return b.Call("min", ctx.Clone(arg), unsigned_max);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
if (array_arg_idx >= 0) {
|
||||||
|
// let array_idx = u32(array-arg)
|
||||||
|
auto* arg = expr->args[static_cast<size_t>(array_arg_idx)];
|
||||||
|
auto* num_layers = b.Call(sem::BuiltinType::kTextureNumLayers, ctx.Clone(texture_arg));
|
||||||
|
auto array_idx = b.Symbols().New("array_idx");
|
||||||
|
hoist.InsertBefore(stmt, b.Decl(b.Let(array_idx, CastToUnsigned(ctx.Clone(arg), 1u))));
|
||||||
|
|
||||||
|
// predicate: array_idx < textureNumLayers(texture)
|
||||||
|
predicate = And(predicate, b.LessThan(array_idx, num_layers));
|
||||||
|
|
||||||
|
// Replace the array index argument with `array_idx`
|
||||||
|
ctx.Replace(arg, b.Expr(array_idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (predicate) {
|
||||||
|
PredicateCall(call, predicate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Applies bounds clamping to the coordinates, array index and level arguments of the texture
|
||||||
|
/// builtin.
|
||||||
|
void ClampTextureBuiltin(const sem::Call* call, const sem::Builtin* builtin) {
|
||||||
|
if (!TextureBuiltinNeedsRobustness(builtin->Type())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* expr = call->Declaration();
|
||||||
|
auto* stmt = call->Stmt();
|
||||||
|
|
||||||
|
// Indices of the mandatory texture and coords parameters, and the optional
|
||||||
|
// array and level parameters.
|
||||||
|
auto& signature = builtin->Signature();
|
||||||
|
auto texture_arg_idx = signature.IndexOf(sem::ParameterUsage::kTexture);
|
||||||
|
auto coords_arg_idx = signature.IndexOf(sem::ParameterUsage::kCoords);
|
||||||
|
auto array_arg_idx = signature.IndexOf(sem::ParameterUsage::kArrayIndex);
|
||||||
|
auto level_arg_idx = signature.IndexOf(sem::ParameterUsage::kLevel);
|
||||||
|
|
||||||
|
auto* texture_arg = expr->args[static_cast<size_t>(texture_arg_idx)];
|
||||||
|
|
||||||
|
// If the level is provided, then we need to clamp this. As the level is used by
|
||||||
|
// textureDimensions() and the texture[Load|Store]() calls, we need to clamp both usages.
|
||||||
|
Symbol level_idx;
|
||||||
|
if (level_arg_idx >= 0) {
|
||||||
|
const auto* param = builtin->Parameters()[static_cast<size_t>(level_arg_idx)];
|
||||||
|
if (param->Type()->is_integer_scalar()) {
|
||||||
|
const auto* arg = expr->args[static_cast<size_t>(level_arg_idx)];
|
||||||
|
level_idx = b.Symbols().New("level_idx");
|
||||||
|
const auto* num_levels =
|
||||||
|
b.Call(sem::BuiltinType::kTextureNumLevels, ctx.Clone(texture_arg));
|
||||||
|
const auto* max = b.Sub(num_levels, 1_a);
|
||||||
|
hoist.InsertBefore(
|
||||||
|
stmt, b.Decl(b.Let(level_idx, b.Call(sem::BuiltinType::kMin,
|
||||||
|
b.Call<u32>(ctx.Clone(arg)), max))));
|
||||||
|
ctx.Replace(arg, b.Expr(level_idx));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clamp the coordinates argument
|
// Clamp the coordinates argument
|
||||||
{
|
if (coords_arg_idx >= 0) {
|
||||||
const auto* target_ty = coords_ty;
|
const auto* param = builtin->Parameters()[static_cast<size_t>(coords_arg_idx)];
|
||||||
const auto width = width_of(target_ty);
|
if (param->Type()->is_integer_scalar_or_vector()) {
|
||||||
const auto* texture_dims =
|
auto* arg = expr->args[static_cast<size_t>(coords_arg_idx)];
|
||||||
level_arg ? b.Call("textureDimensions", ctx.Clone(texture_arg), level_arg())
|
const auto width = WidthOf(param->Type());
|
||||||
: b.Call("textureDimensions", ctx.Clone(texture_arg));
|
const auto* dimensions =
|
||||||
|
level_idx.IsValid()
|
||||||
|
? b.Call(sem::BuiltinType::kTextureDimensions, ctx.Clone(texture_arg),
|
||||||
|
level_idx)
|
||||||
|
: b.Call(sem::BuiltinType::kTextureDimensions, ctx.Clone(texture_arg));
|
||||||
|
|
||||||
// TODO(crbug.com/tint/1526) remove when texture_dims returns u32 or vecN<u32>
|
// dimensions is u32 or vecN<u32>
|
||||||
texture_dims = cast_to_unsigned(texture_dims, width);
|
const auto* unsigned_max = b.Sub(dimensions, ScalarOrVec(b.Expr(1_a), width));
|
||||||
|
if (param->Type()->is_signed_integer_scalar_or_vector()) {
|
||||||
// texture_dims is u32 or vecN<u32>
|
const auto* zero = ScalarOrVec(b.Expr(0_a), width);
|
||||||
const auto* unsigned_max = b.Sub(texture_dims, scalar_or_vec(b.Expr(1_a), width));
|
const auto* signed_max = CastToSigned(unsigned_max, width);
|
||||||
if (target_ty->is_signed_integer_scalar_or_vector()) {
|
ctx.Replace(arg,
|
||||||
const auto* zero = scalar_or_vec(b.Expr(0_a), width);
|
b.Call(sem::BuiltinType::kClamp, ctx.Clone(arg), zero, signed_max));
|
||||||
const auto* signed_max = cast_to_signed(unsigned_max, width);
|
|
||||||
ctx.Replace(coords_arg, b.Call("clamp", ctx.Clone(coords_arg), zero, signed_max));
|
|
||||||
} else {
|
} else {
|
||||||
ctx.Replace(coords_arg, b.Call("min", ctx.Clone(coords_arg), unsigned_max));
|
ctx.Replace(arg, b.Call(sem::BuiltinType::kMin, ctx.Clone(arg), unsigned_max));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clamp the array_index argument, if provided
|
// Clamp the array_index argument, if provided
|
||||||
if (array_idx >= 0) {
|
if (array_arg_idx >= 0) {
|
||||||
auto* target_ty = builtin->Parameters()[static_cast<size_t>(array_idx)]->Type();
|
auto* param = builtin->Parameters()[static_cast<size_t>(array_arg_idx)];
|
||||||
auto* arg = expr->args[static_cast<size_t>(array_idx)];
|
auto* arg = expr->args[static_cast<size_t>(array_arg_idx)];
|
||||||
auto* num_layers = b.Call("textureNumLayers", ctx.Clone(texture_arg));
|
auto* num_layers = b.Call(sem::BuiltinType::kTextureNumLayers, ctx.Clone(texture_arg));
|
||||||
|
|
||||||
// TODO(crbug.com/tint/1526) remove when num_layers returns u32
|
|
||||||
num_layers = cast_to_unsigned(num_layers, 1u);
|
|
||||||
|
|
||||||
const auto* unsigned_max = b.Sub(num_layers, 1_a);
|
const auto* unsigned_max = b.Sub(num_layers, 1_a);
|
||||||
if (target_ty->is_signed_integer_scalar()) {
|
if (param->Type()->is_signed_integer_scalar()) {
|
||||||
const auto* signed_max = cast_to_signed(unsigned_max, 1u);
|
const auto* signed_max = CastToSigned(unsigned_max, 1u);
|
||||||
ctx.Replace(arg, b.Call("clamp", ctx.Clone(arg), 0_a, signed_max));
|
ctx.Replace(arg, b.Call(sem::BuiltinType::kClamp, ctx.Clone(arg), 0_a, signed_max));
|
||||||
} else {
|
} else {
|
||||||
ctx.Replace(arg, b.Call("min", ctx.Clone(arg), unsigned_max));
|
ctx.Replace(arg, b.Call(sem::BuiltinType::kMin, ctx.Clone(arg), unsigned_max));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clamp the level argument, if provided
|
/// @param type builtin type
|
||||||
if (level_idx >= 0) {
|
/// @returns true if the given builtin is a texture function that requires predication or
|
||||||
auto* arg = expr->args[static_cast<size_t>(level_idx)];
|
/// clamping of arguments.
|
||||||
ctx.Replace(arg, level_arg ? level_arg() : b.Expr(0_a));
|
bool TextureBuiltinNeedsRobustness(sem::BuiltinType type) {
|
||||||
|
return type == sem::BuiltinType::kTextureLoad || type == sem::BuiltinType::kTextureStore ||
|
||||||
|
type == sem::BuiltinType::kTextureDimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr; // Clone, which will use the argument replacements above.
|
/// @returns a bitwise and of the two expressions, or the other expression if one is null.
|
||||||
|
const ast::Expression* And(const ast::Expression* lhs, const ast::Expression* rhs) {
|
||||||
|
if (lhs && rhs) {
|
||||||
|
return b.And(lhs, rhs);
|
||||||
|
}
|
||||||
|
if (lhs) {
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transforms a call statement or expression so that the expression is predicated by @p
|
||||||
|
/// predicate.
|
||||||
|
/// @param else_stmt - the statement to execute for the predication failure
|
||||||
|
void PredicateCall(const sem::Call* call,
|
||||||
|
const ast::Expression* predicate,
|
||||||
|
const ast::BlockStatement* else_stmt = nullptr) {
|
||||||
|
auto* expr = call->Declaration();
|
||||||
|
auto* stmt = call->Stmt();
|
||||||
|
auto* call_stmt = stmt->Declaration()->As<ast::CallStatement>();
|
||||||
|
if (call_stmt && call_stmt->expr == expr) {
|
||||||
|
// Wrap the statement in an if-statement with the predicate condition.
|
||||||
|
hoist.Replace(stmt, b.If(predicate, b.Block(ctx.Clone(stmt->Declaration())),
|
||||||
|
ProgramBuilder::ElseStmt(else_stmt)));
|
||||||
|
} else {
|
||||||
|
// Emit the following before the expression's statement:
|
||||||
|
// var predicated_value : return-type;
|
||||||
|
// if (predicate) {
|
||||||
|
// predicated_value = call(...);
|
||||||
|
// }
|
||||||
|
auto value = b.Symbols().New("predicated_value");
|
||||||
|
hoist.InsertBefore(stmt, b.Decl(b.Var(value, CreateASTTypeFor(ctx, call->Type()))));
|
||||||
|
hoist.InsertBefore(stmt, b.If(predicate, b.Block(b.Assign(value, ctx.Clone(expr))),
|
||||||
|
ProgramBuilder::ElseStmt(else_stmt)));
|
||||||
|
|
||||||
|
// Replace the call expression with `predicated_value`
|
||||||
|
ctx.Replace(expr, b.Expr(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns true if @p action is enabled for any address space
|
||||||
|
bool HasAction(Action action) const {
|
||||||
|
return action == cfg.function_action || //
|
||||||
|
action == cfg.texture_action || //
|
||||||
|
action == cfg.private_action || //
|
||||||
|
action == cfg.push_constant_action || //
|
||||||
|
action == cfg.storage_action || //
|
||||||
|
action == cfg.uniform_action || //
|
||||||
|
action == cfg.workgroup_action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns the robustness action to perform for an OOB access with the expression @p expr
|
||||||
|
Action ActionFor(const sem::ValueExpression* expr) {
|
||||||
|
return Switch(
|
||||||
|
expr->Type(), //
|
||||||
|
[&](const type::Reference* t) { return ActionFor(t->AddressSpace()); },
|
||||||
|
[&](Default) { return cfg.value_action; });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns the robustness action to perform for an OOB access in the address space @p
|
||||||
|
/// address_space
|
||||||
|
Action ActionFor(builtin::AddressSpace address_space) {
|
||||||
|
switch (address_space) {
|
||||||
|
case builtin::AddressSpace::kFunction:
|
||||||
|
return cfg.function_action;
|
||||||
|
case builtin::AddressSpace::kHandle:
|
||||||
|
return cfg.texture_action;
|
||||||
|
case builtin::AddressSpace::kPrivate:
|
||||||
|
return cfg.private_action;
|
||||||
|
case builtin::AddressSpace::kPushConstant:
|
||||||
|
return cfg.push_constant_action;
|
||||||
|
case builtin::AddressSpace::kStorage:
|
||||||
|
return cfg.storage_action;
|
||||||
|
case builtin::AddressSpace::kUniform:
|
||||||
|
return cfg.uniform_action;
|
||||||
|
case builtin::AddressSpace::kWorkgroup:
|
||||||
|
return cfg.workgroup_action;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TINT_UNREACHABLE(Transform, b.Diagnostics()) << "unhandled address space" << address_space;
|
||||||
|
return Action::kDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns the vector width of @p ty, or 1 if @p ty is not a vector
|
||||||
|
static uint32_t WidthOf(const type::Type* ty) {
|
||||||
|
if (auto* vec = ty->As<type::Vector>()) {
|
||||||
|
return vec->Width();
|
||||||
|
}
|
||||||
|
return 1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns a scalar or vector type with the element type @p scalar and width @p width
|
||||||
|
ast::Type ScalarOrVecTy(ast::Type scalar, uint32_t width) const {
|
||||||
|
if (width > 1) {
|
||||||
|
return b.ty.vec(scalar, width);
|
||||||
|
}
|
||||||
|
return scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns a vector constructed with the scalar expression @p scalar if @p width > 1,
|
||||||
|
/// otherwise returns @p scalar.
|
||||||
|
const ast::Expression* ScalarOrVec(const ast::Expression* scalar, uint32_t width) {
|
||||||
|
if (width > 1) {
|
||||||
|
return b.Call(b.ty.vec<Infer>(width), scalar);
|
||||||
|
}
|
||||||
|
return scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns @p val cast to a `vecN<i32>`, where `N` is @p width, or cast to i32 if @p width
|
||||||
|
/// is 1.
|
||||||
|
const ast::CallExpression* CastToSigned(const ast::Expression* val, uint32_t width) {
|
||||||
|
return b.Call(ScalarOrVecTy(b.ty.i32(), width), val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns @p val cast to a `vecN<u32>`, where `N` is @p width, or cast to u32 if @p width
|
||||||
|
/// is 1.
|
||||||
|
const ast::CallExpression* CastToUnsigned(const ast::Expression* val, uint32_t width) {
|
||||||
|
return b.Call(ScalarOrVecTy(b.ty.u32(), width), val);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -294,19 +689,7 @@ Transform::ApplyResult Robustness::Apply(const Program* src,
|
||||||
cfg = *cfg_data;
|
cfg = *cfg_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<builtin::AddressSpace> omitted_address_spaces;
|
return State{src, std::move(cfg)}.Run();
|
||||||
for (auto sc : cfg.omitted_address_spaces) {
|
|
||||||
switch (sc) {
|
|
||||||
case AddressSpace::kUniform:
|
|
||||||
omitted_address_spaces.insert(builtin::AddressSpace::kUniform);
|
|
||||||
break;
|
|
||||||
case AddressSpace::kStorage:
|
|
||||||
omitted_address_spaces.insert(builtin::AddressSpace::kStorage);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return State{src, std::move(omitted_address_spaces)}.Run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tint::transform
|
} // namespace tint::transform
|
||||||
|
|
|
@ -15,29 +15,33 @@
|
||||||
#ifndef SRC_TINT_TRANSFORM_ROBUSTNESS_H_
|
#ifndef SRC_TINT_TRANSFORM_ROBUSTNESS_H_
|
||||||
#define SRC_TINT_TRANSFORM_ROBUSTNESS_H_
|
#define SRC_TINT_TRANSFORM_ROBUSTNESS_H_
|
||||||
|
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
#include "src/tint/transform/transform.h"
|
#include "src/tint/transform/transform.h"
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
namespace tint::ast {
|
|
||||||
class IndexAccessorExpression;
|
|
||||||
class CallExpression;
|
|
||||||
} // namespace tint::ast
|
|
||||||
|
|
||||||
namespace tint::transform {
|
namespace tint::transform {
|
||||||
|
|
||||||
/// This transform is responsible for clamping all array accesses to be within
|
/// This transform is responsible for ensuring that all out of bounds accesses are prevented,
|
||||||
/// the bounds of the array. Any access before the start of the array will clamp
|
/// either by conditioning the access (predication) or through clamping of the index to keep the
|
||||||
/// to zero and any access past the end of the array will clamp to
|
/// access in bounds.
|
||||||
/// (array length - 1).
|
/// @note Robustness must come after:
|
||||||
/// @note This transform must come before the BuiltinPolyfill transform
|
/// * PromoteSideEffectsToDecl as Robustness requires side-effecting expressions to be hoisted
|
||||||
|
/// to their own statements.
|
||||||
|
/// Robustness must come before:
|
||||||
|
/// * BuiltinPolyfill as 'clamp' and binary operators may need to be polyfilled.
|
||||||
|
/// * CanonicalizeEntryPointIO as the transform does not support the 'in' and 'out' address
|
||||||
|
/// spaces.
|
||||||
class Robustness final : public Castable<Robustness, Transform> {
|
class Robustness final : public Castable<Robustness, Transform> {
|
||||||
public:
|
public:
|
||||||
/// Address space to be skipped in the transform
|
/// Robustness action for out-of-bounds indexing.
|
||||||
enum class AddressSpace {
|
enum class Action {
|
||||||
kUniform,
|
/// Do nothing to prevent the out-of-bounds action.
|
||||||
kStorage,
|
kIgnore,
|
||||||
|
/// Clamp the index to be within bounds.
|
||||||
|
kClamp,
|
||||||
|
/// Do not execute the read or write if the index is out-of-bounds.
|
||||||
|
kPredicate,
|
||||||
|
|
||||||
|
/// The default action
|
||||||
|
kDefault = kClamp,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Configuration options for the transform
|
/// Configuration options for the transform
|
||||||
|
@ -55,9 +59,24 @@ class Robustness final : public Castable<Robustness, Transform> {
|
||||||
/// @returns this Config
|
/// @returns this Config
|
||||||
Config& operator=(const Config&);
|
Config& operator=(const Config&);
|
||||||
|
|
||||||
/// Address spaces to omit from apply the transform to.
|
/// Robustness action for values
|
||||||
/// This allows for optimizing on hardware that provide safe accesses.
|
Action value_action = Action::kDefault;
|
||||||
std::unordered_set<AddressSpace> omitted_address_spaces;
|
|
||||||
|
/// Robustness action for non-sampling texture operations
|
||||||
|
Action texture_action = Action::kDefault;
|
||||||
|
|
||||||
|
/// Robustness action for variables in the 'function' address space
|
||||||
|
Action function_action = Action::kDefault;
|
||||||
|
/// Robustness action for variables in the 'private' address space
|
||||||
|
Action private_action = Action::kDefault;
|
||||||
|
/// Robustness action for variables in the 'push_constant' address space
|
||||||
|
Action push_constant_action = Action::kDefault;
|
||||||
|
/// Robustness action for variables in the 'storage' address space
|
||||||
|
Action storage_action = Action::kDefault;
|
||||||
|
/// Robustness action for variables in the 'uniform' address space
|
||||||
|
Action uniform_action = Action::kDefault;
|
||||||
|
/// Robustness action for variables in the 'workgroup' address space
|
||||||
|
Action workgroup_action = Action::kDefault;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -166,7 +166,8 @@ SanitizedResult Sanitize(const Program* in,
|
||||||
manager.Add<transform::PromoteSideEffectsToDecl>();
|
manager.Add<transform::PromoteSideEffectsToDecl>();
|
||||||
|
|
||||||
if (!options.disable_robustness) {
|
if (!options.disable_robustness) {
|
||||||
// Robustness must come before BuiltinPolyfill
|
// Robustness must come after PromoteSideEffectsToDecl
|
||||||
|
// Robustness must come before BuiltinPolyfill and CanonicalizeEntryPointIO
|
||||||
manager.Add<transform::Robustness>();
|
manager.Add<transform::Robustness>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,8 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
|
||||||
manager.Add<transform::PromoteSideEffectsToDecl>();
|
manager.Add<transform::PromoteSideEffectsToDecl>();
|
||||||
|
|
||||||
if (!options.disable_robustness) {
|
if (!options.disable_robustness) {
|
||||||
// Robustness must come before BuiltinPolyfill
|
// Robustness must come after PromoteSideEffectsToDecl
|
||||||
|
// Robustness must come before BuiltinPolyfill and CanonicalizeEntryPointIO
|
||||||
manager.Add<transform::Robustness>();
|
manager.Add<transform::Robustness>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -207,7 +207,8 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
|
||||||
manager.Add<transform::PromoteSideEffectsToDecl>();
|
manager.Add<transform::PromoteSideEffectsToDecl>();
|
||||||
|
|
||||||
if (!options.disable_robustness) {
|
if (!options.disable_robustness) {
|
||||||
// Robustness must come before BuiltinPolyfill
|
// Robustness must come after PromoteSideEffectsToDecl
|
||||||
|
// Robustness must come before BuiltinPolyfill and CanonicalizeEntryPointIO
|
||||||
manager.Add<transform::Robustness>();
|
manager.Add<transform::Robustness>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,8 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
|
||||||
manager.Add<transform::MergeReturn>();
|
manager.Add<transform::MergeReturn>();
|
||||||
|
|
||||||
if (!options.disable_robustness) {
|
if (!options.disable_robustness) {
|
||||||
// Robustness must come before BuiltinPolyfill
|
// Robustness must come after PromoteSideEffectsToDecl
|
||||||
|
// Robustness must come before BuiltinPolyfill and CanonicalizeEntryPointIO
|
||||||
manager.Add<transform::Robustness>();
|
manager.Add<transform::Robustness>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
int tint_clamp(int e, int low, int high) {
|
int2 tint_clamp(int2 e, int2 low, int2 high) {
|
||||||
return min(max(e, low), high);
|
|
||||||
}
|
|
||||||
|
|
||||||
int2 tint_clamp_1(int2 e, int2 low, int2 high) {
|
|
||||||
return min(max(e, low), high);
|
return min(max(e, low), high);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,26 +41,23 @@ float4 textureLoadExternal(Texture2D<float4> plane0, Texture2D<float4> plane1, i
|
||||||
float3 color = float3(0.0f, 0.0f, 0.0f);
|
float3 color = float3(0.0f, 0.0f, 0.0f);
|
||||||
if ((params.numPlanes == 1u)) {
|
if ((params.numPlanes == 1u)) {
|
||||||
int3 tint_tmp;
|
int3 tint_tmp;
|
||||||
|
plane0.GetDimensions(0, tint_tmp.x, tint_tmp.y, tint_tmp.z);
|
||||||
|
const uint level_idx = min(0u, (tint_tmp.z - 1u));
|
||||||
int3 tint_tmp_1;
|
int3 tint_tmp_1;
|
||||||
plane0.GetDimensions(0, tint_tmp_1.x, tint_tmp_1.y, tint_tmp_1.z);
|
plane0.GetDimensions(level_idx, tint_tmp_1.x, tint_tmp_1.y, tint_tmp_1.z);
|
||||||
plane0.GetDimensions(tint_clamp(0, 0, int((uint(tint_tmp_1.z) - 1u))), tint_tmp.x, tint_tmp.y, tint_tmp.z);
|
color = plane0.Load(int3(tint_clamp(coord, (0).xx, int2((tint_tmp_1.xy - (1u).xx))), int(level_idx))).rgb;
|
||||||
|
} else {
|
||||||
int3 tint_tmp_2;
|
int3 tint_tmp_2;
|
||||||
plane0.GetDimensions(0, tint_tmp_2.x, tint_tmp_2.y, tint_tmp_2.z);
|
plane0.GetDimensions(0, tint_tmp_2.x, tint_tmp_2.y, tint_tmp_2.z);
|
||||||
color = plane0.Load(int3(tint_clamp_1(coord, (0).xx, int2((uint2(tint_tmp.xy) - (1u).xx))), tint_clamp(0, 0, int((uint(tint_tmp_2.z) - 1u))))).rgb;
|
const uint level_idx_1 = min(0u, (tint_tmp_2.z - 1u));
|
||||||
} else {
|
|
||||||
int3 tint_tmp_3;
|
int3 tint_tmp_3;
|
||||||
|
plane1.GetDimensions(0, tint_tmp_3.x, tint_tmp_3.y, tint_tmp_3.z);
|
||||||
|
const uint level_idx_2 = min(0u, (tint_tmp_3.z - 1u));
|
||||||
int3 tint_tmp_4;
|
int3 tint_tmp_4;
|
||||||
plane0.GetDimensions(0, tint_tmp_4.x, tint_tmp_4.y, tint_tmp_4.z);
|
plane0.GetDimensions(level_idx_1, tint_tmp_4.x, tint_tmp_4.y, tint_tmp_4.z);
|
||||||
plane0.GetDimensions(tint_clamp(0, 0, int((uint(tint_tmp_4.z) - 1u))), tint_tmp_3.x, tint_tmp_3.y, tint_tmp_3.z);
|
|
||||||
int3 tint_tmp_5;
|
int3 tint_tmp_5;
|
||||||
plane0.GetDimensions(0, tint_tmp_5.x, tint_tmp_5.y, tint_tmp_5.z);
|
plane1.GetDimensions(level_idx_2, tint_tmp_5.x, tint_tmp_5.y, tint_tmp_5.z);
|
||||||
int3 tint_tmp_6;
|
color = mul(params.yuvToRgbConversionMatrix, float4(plane0.Load(int3(tint_clamp(coord, (0).xx, int2((tint_tmp_4.xy - (1u).xx))), int(level_idx_1))).r, plane1.Load(int3(tint_clamp(coord1, (0).xx, int2((tint_tmp_5.xy - (1u).xx))), int(level_idx_2))).rg, 1.0f));
|
||||||
int3 tint_tmp_7;
|
|
||||||
plane1.GetDimensions(0, tint_tmp_7.x, tint_tmp_7.y, tint_tmp_7.z);
|
|
||||||
plane1.GetDimensions(tint_clamp(0, 0, int((uint(tint_tmp_7.z) - 1u))), tint_tmp_6.x, tint_tmp_6.y, tint_tmp_6.z);
|
|
||||||
int3 tint_tmp_8;
|
|
||||||
plane1.GetDimensions(0, tint_tmp_8.x, tint_tmp_8.y, tint_tmp_8.z);
|
|
||||||
color = mul(params.yuvToRgbConversionMatrix, float4(plane0.Load(int3(tint_clamp_1(coord, (0).xx, int2((uint2(tint_tmp_3.xy) - (1u).xx))), tint_clamp(0, 0, int((uint(tint_tmp_5.z) - 1u))))).r, plane1.Load(int3(tint_clamp_1(coord1, (0).xx, int2((uint2(tint_tmp_6.xy) - (1u).xx))), tint_clamp(0, 0, int((uint(tint_tmp_8.z) - 1u))))).rg, 1.0f));
|
|
||||||
}
|
}
|
||||||
if ((params.doYuvToRgbConversionOnly == 0u)) {
|
if ((params.doYuvToRgbConversionOnly == 0u)) {
|
||||||
color = gammaCorrection(color, params.gammaDecodeParams);
|
color = gammaCorrection(color, params.gammaDecodeParams);
|
||||||
|
@ -121,12 +114,12 @@ ExternalTextureParams ext_tex_params_load(uint offset) {
|
||||||
[numthreads(1, 1, 1)]
|
[numthreads(1, 1, 1)]
|
||||||
void main() {
|
void main() {
|
||||||
float4 red = textureLoadExternal(t, ext_tex_plane_1, (10).xx, ext_tex_params_load(0u));
|
float4 red = textureLoadExternal(t, ext_tex_plane_1, (10).xx, ext_tex_params_load(0u));
|
||||||
int2 tint_tmp_9;
|
int2 tint_tmp_6;
|
||||||
outImage.GetDimensions(tint_tmp_9.x, tint_tmp_9.y);
|
outImage.GetDimensions(tint_tmp_6.x, tint_tmp_6.y);
|
||||||
outImage[tint_clamp_1((0).xx, (0).xx, int2((uint2(tint_tmp_9) - (1u).xx)))] = red;
|
outImage[tint_clamp((0).xx, (0).xx, int2((tint_tmp_6 - (1u).xx)))] = red;
|
||||||
float4 green = textureLoadExternal(t, ext_tex_plane_1, int2(70, 118), ext_tex_params_load(0u));
|
float4 green = textureLoadExternal(t, ext_tex_plane_1, int2(70, 118), ext_tex_params_load(0u));
|
||||||
int2 tint_tmp_10;
|
int2 tint_tmp_7;
|
||||||
outImage.GetDimensions(tint_tmp_10.x, tint_tmp_10.y);
|
outImage.GetDimensions(tint_tmp_7.x, tint_tmp_7.y);
|
||||||
outImage[tint_clamp_1(int2(1, 0), (0).xx, int2((uint2(tint_tmp_10) - (1u).xx)))] = green;
|
outImage[tint_clamp(int2(1, 0), (0).xx, int2((tint_tmp_7 - (1u).xx)))] = green;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
int tint_clamp(int e, int low, int high) {
|
int2 tint_clamp(int2 e, int2 low, int2 high) {
|
||||||
return min(max(e, low), high);
|
|
||||||
}
|
|
||||||
|
|
||||||
int2 tint_clamp_1(int2 e, int2 low, int2 high) {
|
|
||||||
return min(max(e, low), high);
|
return min(max(e, low), high);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,26 +41,23 @@ float4 textureLoadExternal(Texture2D<float4> plane0, Texture2D<float4> plane1, i
|
||||||
float3 color = float3(0.0f, 0.0f, 0.0f);
|
float3 color = float3(0.0f, 0.0f, 0.0f);
|
||||||
if ((params.numPlanes == 1u)) {
|
if ((params.numPlanes == 1u)) {
|
||||||
int3 tint_tmp;
|
int3 tint_tmp;
|
||||||
|
plane0.GetDimensions(0, tint_tmp.x, tint_tmp.y, tint_tmp.z);
|
||||||
|
const uint level_idx = min(0u, (tint_tmp.z - 1u));
|
||||||
int3 tint_tmp_1;
|
int3 tint_tmp_1;
|
||||||
plane0.GetDimensions(0, tint_tmp_1.x, tint_tmp_1.y, tint_tmp_1.z);
|
plane0.GetDimensions(level_idx, tint_tmp_1.x, tint_tmp_1.y, tint_tmp_1.z);
|
||||||
plane0.GetDimensions(tint_clamp(0, 0, int((uint(tint_tmp_1.z) - 1u))), tint_tmp.x, tint_tmp.y, tint_tmp.z);
|
color = plane0.Load(int3(tint_clamp(coord, (0).xx, int2((tint_tmp_1.xy - (1u).xx))), int(level_idx))).rgb;
|
||||||
|
} else {
|
||||||
int3 tint_tmp_2;
|
int3 tint_tmp_2;
|
||||||
plane0.GetDimensions(0, tint_tmp_2.x, tint_tmp_2.y, tint_tmp_2.z);
|
plane0.GetDimensions(0, tint_tmp_2.x, tint_tmp_2.y, tint_tmp_2.z);
|
||||||
color = plane0.Load(int3(tint_clamp_1(coord, (0).xx, int2((uint2(tint_tmp.xy) - (1u).xx))), tint_clamp(0, 0, int((uint(tint_tmp_2.z) - 1u))))).rgb;
|
const uint level_idx_1 = min(0u, (tint_tmp_2.z - 1u));
|
||||||
} else {
|
|
||||||
int3 tint_tmp_3;
|
int3 tint_tmp_3;
|
||||||
|
plane1.GetDimensions(0, tint_tmp_3.x, tint_tmp_3.y, tint_tmp_3.z);
|
||||||
|
const uint level_idx_2 = min(0u, (tint_tmp_3.z - 1u));
|
||||||
int3 tint_tmp_4;
|
int3 tint_tmp_4;
|
||||||
plane0.GetDimensions(0, tint_tmp_4.x, tint_tmp_4.y, tint_tmp_4.z);
|
plane0.GetDimensions(level_idx_1, tint_tmp_4.x, tint_tmp_4.y, tint_tmp_4.z);
|
||||||
plane0.GetDimensions(tint_clamp(0, 0, int((uint(tint_tmp_4.z) - 1u))), tint_tmp_3.x, tint_tmp_3.y, tint_tmp_3.z);
|
|
||||||
int3 tint_tmp_5;
|
int3 tint_tmp_5;
|
||||||
plane0.GetDimensions(0, tint_tmp_5.x, tint_tmp_5.y, tint_tmp_5.z);
|
plane1.GetDimensions(level_idx_2, tint_tmp_5.x, tint_tmp_5.y, tint_tmp_5.z);
|
||||||
int3 tint_tmp_6;
|
color = mul(params.yuvToRgbConversionMatrix, float4(plane0.Load(int3(tint_clamp(coord, (0).xx, int2((tint_tmp_4.xy - (1u).xx))), int(level_idx_1))).r, plane1.Load(int3(tint_clamp(coord1, (0).xx, int2((tint_tmp_5.xy - (1u).xx))), int(level_idx_2))).rg, 1.0f));
|
||||||
int3 tint_tmp_7;
|
|
||||||
plane1.GetDimensions(0, tint_tmp_7.x, tint_tmp_7.y, tint_tmp_7.z);
|
|
||||||
plane1.GetDimensions(tint_clamp(0, 0, int((uint(tint_tmp_7.z) - 1u))), tint_tmp_6.x, tint_tmp_6.y, tint_tmp_6.z);
|
|
||||||
int3 tint_tmp_8;
|
|
||||||
plane1.GetDimensions(0, tint_tmp_8.x, tint_tmp_8.y, tint_tmp_8.z);
|
|
||||||
color = mul(params.yuvToRgbConversionMatrix, float4(plane0.Load(int3(tint_clamp_1(coord, (0).xx, int2((uint2(tint_tmp_3.xy) - (1u).xx))), tint_clamp(0, 0, int((uint(tint_tmp_5.z) - 1u))))).r, plane1.Load(int3(tint_clamp_1(coord1, (0).xx, int2((uint2(tint_tmp_6.xy) - (1u).xx))), tint_clamp(0, 0, int((uint(tint_tmp_8.z) - 1u))))).rg, 1.0f));
|
|
||||||
}
|
}
|
||||||
if ((params.doYuvToRgbConversionOnly == 0u)) {
|
if ((params.doYuvToRgbConversionOnly == 0u)) {
|
||||||
color = gammaCorrection(color, params.gammaDecodeParams);
|
color = gammaCorrection(color, params.gammaDecodeParams);
|
||||||
|
@ -121,12 +114,12 @@ ExternalTextureParams ext_tex_params_load(uint offset) {
|
||||||
[numthreads(1, 1, 1)]
|
[numthreads(1, 1, 1)]
|
||||||
void main() {
|
void main() {
|
||||||
float4 red = textureLoadExternal(t, ext_tex_plane_1, (10).xx, ext_tex_params_load(0u));
|
float4 red = textureLoadExternal(t, ext_tex_plane_1, (10).xx, ext_tex_params_load(0u));
|
||||||
int2 tint_tmp_9;
|
int2 tint_tmp_6;
|
||||||
outImage.GetDimensions(tint_tmp_9.x, tint_tmp_9.y);
|
outImage.GetDimensions(tint_tmp_6.x, tint_tmp_6.y);
|
||||||
outImage[tint_clamp_1((0).xx, (0).xx, int2((uint2(tint_tmp_9) - (1u).xx)))] = red;
|
outImage[tint_clamp((0).xx, (0).xx, int2((tint_tmp_6 - (1u).xx)))] = red;
|
||||||
float4 green = textureLoadExternal(t, ext_tex_plane_1, int2(70, 118), ext_tex_params_load(0u));
|
float4 green = textureLoadExternal(t, ext_tex_plane_1, int2(70, 118), ext_tex_params_load(0u));
|
||||||
int2 tint_tmp_10;
|
int2 tint_tmp_7;
|
||||||
outImage.GetDimensions(tint_tmp_10.x, tint_tmp_10.y);
|
outImage.GetDimensions(tint_tmp_7.x, tint_tmp_7.y);
|
||||||
outImage[tint_clamp_1(int2(1, 0), (0).xx, int2((uint2(tint_tmp_10) - (1u).xx)))] = green;
|
outImage[tint_clamp(int2(1, 0), (0).xx, int2((tint_tmp_7 - (1u).xx)))] = green;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,11 +72,7 @@ ExternalTextureParams tint_unpack_vec3_in_composite_1(ExternalTextureParams_tint
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tint_clamp(int e, int low, int high) {
|
int2 tint_clamp(int2 e, int2 low, int2 high) {
|
||||||
return min(max(e, low), high);
|
|
||||||
}
|
|
||||||
|
|
||||||
int2 tint_clamp_1(int2 e, int2 low, int2 high) {
|
|
||||||
return min(max(e, low), high);
|
return min(max(e, low), high);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,9 +87,12 @@ float4 textureLoadExternal(texture2d<float, access::sample> plane0, texture2d<fl
|
||||||
int2 const coord1 = (coord >> uint2(1u));
|
int2 const coord1 = (coord >> uint2(1u));
|
||||||
float3 color = 0.0f;
|
float3 color = 0.0f;
|
||||||
if ((params.numPlanes == 1u)) {
|
if ((params.numPlanes == 1u)) {
|
||||||
color = plane0.read(uint2(tint_clamp_1(coord, int2(0), int2((uint2(uint2(plane0.get_width(tint_clamp(0, 0, int((uint(plane0.get_num_mip_levels()) - 1u)))), plane0.get_height(tint_clamp(0, 0, int((uint(plane0.get_num_mip_levels()) - 1u)))))) - uint2(1u))))), tint_clamp(0, 0, int((uint(plane0.get_num_mip_levels()) - 1u)))).rgb;
|
uint const level_idx = min(0u, (plane0.get_num_mip_levels() - 1u));
|
||||||
|
color = plane0.read(uint2(tint_clamp(coord, int2(0), int2((uint2(plane0.get_width(level_idx), plane0.get_height(level_idx)) - uint2(1u))))), level_idx).rgb;
|
||||||
} else {
|
} else {
|
||||||
color = (float4(plane0.read(uint2(tint_clamp_1(coord, int2(0), int2((uint2(uint2(plane0.get_width(tint_clamp(0, 0, int((uint(plane0.get_num_mip_levels()) - 1u)))), plane0.get_height(tint_clamp(0, 0, int((uint(plane0.get_num_mip_levels()) - 1u)))))) - uint2(1u))))), tint_clamp(0, 0, int((uint(plane0.get_num_mip_levels()) - 1u))))[0], plane1.read(uint2(tint_clamp_1(coord1, int2(0), int2((uint2(uint2(plane1.get_width(tint_clamp(0, 0, int((uint(plane1.get_num_mip_levels()) - 1u)))), plane1.get_height(tint_clamp(0, 0, int((uint(plane1.get_num_mip_levels()) - 1u)))))) - uint2(1u))))), tint_clamp(0, 0, int((uint(plane1.get_num_mip_levels()) - 1u)))).rg, 1.0f) * params.yuvToRgbConversionMatrix);
|
uint const level_idx_1 = min(0u, (plane0.get_num_mip_levels() - 1u));
|
||||||
|
uint const level_idx_2 = min(0u, (plane1.get_num_mip_levels() - 1u));
|
||||||
|
color = (float4(plane0.read(uint2(tint_clamp(coord, int2(0), int2((uint2(plane0.get_width(level_idx_1), plane0.get_height(level_idx_1)) - uint2(1u))))), level_idx_1)[0], plane1.read(uint2(tint_clamp(coord1, int2(0), int2((uint2(plane1.get_width(level_idx_2), plane1.get_height(level_idx_2)) - uint2(1u))))), level_idx_2).rg, 1.0f) * params.yuvToRgbConversionMatrix);
|
||||||
}
|
}
|
||||||
if ((params.doYuvToRgbConversionOnly == 0u)) {
|
if ((params.doYuvToRgbConversionOnly == 0u)) {
|
||||||
color = gammaCorrection(color, params.gammaDecodeParams);
|
color = gammaCorrection(color, params.gammaDecodeParams);
|
||||||
|
@ -105,9 +104,9 @@ float4 textureLoadExternal(texture2d<float, access::sample> plane0, texture2d<fl
|
||||||
|
|
||||||
kernel void tint_symbol(texture2d<float, access::sample> tint_symbol_1 [[texture(0)]], texture2d<float, access::sample> tint_symbol_2 [[texture(1)]], const constant ExternalTextureParams_tint_packed_vec3* tint_symbol_3 [[buffer(0)]], texture2d<float, access::write> tint_symbol_4 [[texture(2)]]) {
|
kernel void tint_symbol(texture2d<float, access::sample> tint_symbol_1 [[texture(0)]], texture2d<float, access::sample> tint_symbol_2 [[texture(1)]], const constant ExternalTextureParams_tint_packed_vec3* tint_symbol_3 [[buffer(0)]], texture2d<float, access::write> tint_symbol_4 [[texture(2)]]) {
|
||||||
float4 red = textureLoadExternal(tint_symbol_1, tint_symbol_2, int2(10), tint_unpack_vec3_in_composite_1(*(tint_symbol_3)));
|
float4 red = textureLoadExternal(tint_symbol_1, tint_symbol_2, int2(10), tint_unpack_vec3_in_composite_1(*(tint_symbol_3)));
|
||||||
tint_symbol_4.write(red, uint2(tint_clamp_1(int2(0), int2(0), int2((uint2(uint2(tint_symbol_4.get_width(), tint_symbol_4.get_height())) - uint2(1u))))));
|
tint_symbol_4.write(red, uint2(tint_clamp(int2(0), int2(0), int2((uint2(tint_symbol_4.get_width(), tint_symbol_4.get_height()) - uint2(1u))))));
|
||||||
float4 green = textureLoadExternal(tint_symbol_1, tint_symbol_2, int2(70, 118), tint_unpack_vec3_in_composite_1(*(tint_symbol_3)));
|
float4 green = textureLoadExternal(tint_symbol_1, tint_symbol_2, int2(70, 118), tint_unpack_vec3_in_composite_1(*(tint_symbol_3)));
|
||||||
tint_symbol_4.write(green, uint2(tint_clamp_1(int2(1, 0), int2(0), int2((uint2(uint2(tint_symbol_4.get_width(), tint_symbol_4.get_height())) - uint2(1u))))));
|
tint_symbol_4.write(green, uint2(tint_clamp(int2(1, 0), int2(0), int2((uint2(tint_symbol_4.get_width(), tint_symbol_4.get_height()) - uint2(1u))))));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
; SPIR-V
|
; SPIR-V
|
||||||
; Version: 1.3
|
; Version: 1.3
|
||||||
; Generator: Google Tint Compiler; 0
|
; Generator: Google Tint Compiler; 0
|
||||||
; Bound: 237
|
; Bound: 203
|
||||||
; Schema: 0
|
; Schema: 0
|
||||||
OpCapability Shader
|
OpCapability Shader
|
||||||
OpCapability ImageQuery
|
OpCapability ImageQuery
|
||||||
%28 = OpExtInstImport "GLSL.std.450"
|
%29 = OpExtInstImport "GLSL.std.450"
|
||||||
OpMemoryModel Logical GLSL450
|
OpMemoryModel Logical GLSL450
|
||||||
OpEntryPoint GLCompute %main "main"
|
OpEntryPoint GLCompute %main "main"
|
||||||
OpExecutionMode %main LocalSize 1 1 1
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
@ -38,10 +38,6 @@
|
||||||
OpName %e "e"
|
OpName %e "e"
|
||||||
OpName %low "low"
|
OpName %low "low"
|
||||||
OpName %high "high"
|
OpName %high "high"
|
||||||
OpName %tint_clamp_1 "tint_clamp_1"
|
|
||||||
OpName %e_0 "e"
|
|
||||||
OpName %low_0 "low"
|
|
||||||
OpName %high_0 "high"
|
|
||||||
OpName %gammaCorrection "gammaCorrection"
|
OpName %gammaCorrection "gammaCorrection"
|
||||||
OpName %v "v"
|
OpName %v "v"
|
||||||
OpName %params "params"
|
OpName %params "params"
|
||||||
|
@ -130,233 +126,208 @@
|
||||||
%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
|
%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
|
||||||
%outImage = OpVariable %_ptr_UniformConstant_19 UniformConstant
|
%outImage = OpVariable %_ptr_UniformConstant_19 UniformConstant
|
||||||
%int = OpTypeInt 32 1
|
%int = OpTypeInt 32 1
|
||||||
%20 = OpTypeFunction %int %int %int %int
|
|
||||||
%v2int = OpTypeVector %int 2
|
%v2int = OpTypeVector %int 2
|
||||||
%30 = OpTypeFunction %v2int %v2int %v2int %v2int
|
%20 = OpTypeFunction %v2int %v2int %v2int %v2int
|
||||||
%39 = OpTypeFunction %v3float %v3float %GammaTransferParams
|
%31 = OpTypeFunction %v3float %v3float %GammaTransferParams
|
||||||
%bool = OpTypeBool
|
%bool = OpTypeBool
|
||||||
%v3bool = OpTypeVector %bool 3
|
%v3bool = OpTypeVector %bool 3
|
||||||
%_ptr_Function_v3float = OpTypePointer Function %v3float
|
%_ptr_Function_v3float = OpTypePointer Function %v3float
|
||||||
%58 = OpConstantNull %v3float
|
%50 = OpConstantNull %v3float
|
||||||
%mat3v2float = OpTypeMatrix %v2float 3
|
%mat3v2float = OpTypeMatrix %v2float 3
|
||||||
%ExternalTextureParams = OpTypeStruct %uint %uint %mat3v4float %GammaTransferParams %GammaTransferParams %mat3v3float %mat3v2float
|
%ExternalTextureParams = OpTypeStruct %uint %uint %mat3v4float %GammaTransferParams %GammaTransferParams %mat3v3float %mat3v2float
|
||||||
%78 = OpTypeFunction %v4float %3 %3 %v2int %ExternalTextureParams
|
%70 = OpTypeFunction %v4float %3 %3 %v2int %ExternalTextureParams
|
||||||
%v2uint = OpTypeVector %uint 2
|
%v2uint = OpTypeVector %uint 2
|
||||||
%uint_1 = OpConstant %uint 1
|
%uint_1 = OpConstant %uint 1
|
||||||
%89 = OpConstantComposite %v2uint %uint_1 %uint_1
|
%81 = OpConstantComposite %v2uint %uint_1 %uint_1
|
||||||
%99 = OpConstantNull %v2int
|
%90 = OpConstantNull %uint
|
||||||
%104 = OpConstantNull %int
|
%95 = OpConstantNull %v2int
|
||||||
%float_1 = OpConstant %float 1
|
%float_1 = OpConstant %float 1
|
||||||
%157 = OpConstantNull %uint
|
%142 = OpTypeFunction %ExternalTextureParams %ExternalTextureParams_std140
|
||||||
%175 = OpTypeFunction %ExternalTextureParams %ExternalTextureParams_std140
|
|
||||||
%void = OpTypeVoid
|
%void = OpTypeVoid
|
||||||
%190 = OpTypeFunction %void
|
%157 = OpTypeFunction %void
|
||||||
%int_10 = OpConstant %int 10
|
%int_10 = OpConstant %int 10
|
||||||
%198 = OpConstantComposite %v2int %int_10 %int_10
|
%165 = OpConstantComposite %v2int %int_10 %int_10
|
||||||
%uint_0 = OpConstant %uint 0
|
%uint_0 = OpConstant %uint 0
|
||||||
%_ptr_Uniform_ExternalTextureParams_std140 = OpTypePointer Uniform %ExternalTextureParams_std140
|
%_ptr_Uniform_ExternalTextureParams_std140 = OpTypePointer Uniform %ExternalTextureParams_std140
|
||||||
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
||||||
%206 = OpConstantNull %v4float
|
%173 = OpConstantNull %v4float
|
||||||
%int_70 = OpConstant %int 70
|
%int_70 = OpConstant %int 70
|
||||||
%int_118 = OpConstant %int 118
|
%int_118 = OpConstant %int 118
|
||||||
%221 = OpConstantComposite %v2int %int_70 %int_118
|
%187 = OpConstantComposite %v2int %int_70 %int_118
|
||||||
%int_1 = OpConstant %int 1
|
%int_1 = OpConstant %int 1
|
||||||
%230 = OpConstantComposite %v2int %int_1 %104
|
%196 = OpConstantNull %int
|
||||||
%tint_clamp = OpFunction %int None %20
|
%197 = OpConstantComposite %v2int %int_1 %196
|
||||||
%e = OpFunctionParameter %int
|
%tint_clamp = OpFunction %v2int None %20
|
||||||
%low = OpFunctionParameter %int
|
%e = OpFunctionParameter %v2int
|
||||||
%high = OpFunctionParameter %int
|
%low = OpFunctionParameter %v2int
|
||||||
%26 = OpLabel
|
%high = OpFunctionParameter %v2int
|
||||||
%29 = OpExtInst %int %28 SMax %e %low
|
%27 = OpLabel
|
||||||
%27 = OpExtInst %int %28 SMin %29 %high
|
%30 = OpExtInst %v2int %29 SMax %e %low
|
||||||
OpReturnValue %27
|
%28 = OpExtInst %v2int %29 SMin %30 %high
|
||||||
|
OpReturnValue %28
|
||||||
OpFunctionEnd
|
OpFunctionEnd
|
||||||
%tint_clamp_1 = OpFunction %v2int None %30
|
%gammaCorrection = OpFunction %v3float None %31
|
||||||
%e_0 = OpFunctionParameter %v2int
|
|
||||||
%low_0 = OpFunctionParameter %v2int
|
|
||||||
%high_0 = OpFunctionParameter %v2int
|
|
||||||
%36 = OpLabel
|
|
||||||
%38 = OpExtInst %v2int %28 SMax %e_0 %low_0
|
|
||||||
%37 = OpExtInst %v2int %28 SMin %38 %high_0
|
|
||||||
OpReturnValue %37
|
|
||||||
OpFunctionEnd
|
|
||||||
%gammaCorrection = OpFunction %v3float None %39
|
|
||||||
%v = OpFunctionParameter %v3float
|
%v = OpFunctionParameter %v3float
|
||||||
%params = OpFunctionParameter %GammaTransferParams
|
%params = OpFunctionParameter %GammaTransferParams
|
||||||
%43 = OpLabel
|
%35 = OpLabel
|
||||||
%56 = OpVariable %_ptr_Function_v3float Function %58
|
%48 = OpVariable %_ptr_Function_v3float Function %50
|
||||||
%68 = OpVariable %_ptr_Function_v3float Function %58
|
%60 = OpVariable %_ptr_Function_v3float Function %50
|
||||||
%74 = OpVariable %_ptr_Function_v3float Function %58
|
%66 = OpVariable %_ptr_Function_v3float Function %50
|
||||||
%44 = OpExtInst %v3float %28 FAbs %v
|
%36 = OpExtInst %v3float %29 FAbs %v
|
||||||
%45 = OpCompositeExtract %float %params 4
|
%37 = OpCompositeExtract %float %params 4
|
||||||
%46 = OpCompositeConstruct %v3float %45 %45 %45
|
%38 = OpCompositeConstruct %v3float %37 %37 %37
|
||||||
%47 = OpFOrdLessThan %v3bool %44 %46
|
%39 = OpFOrdLessThan %v3bool %36 %38
|
||||||
%50 = OpExtInst %v3float %28 FSign %v
|
%42 = OpExtInst %v3float %29 FSign %v
|
||||||
%51 = OpCompositeExtract %float %params 3
|
%43 = OpCompositeExtract %float %params 3
|
||||||
%52 = OpExtInst %v3float %28 FAbs %v
|
%44 = OpExtInst %v3float %29 FAbs %v
|
||||||
%53 = OpVectorTimesScalar %v3float %52 %51
|
%45 = OpVectorTimesScalar %v3float %44 %43
|
||||||
%54 = OpCompositeExtract %float %params 6
|
%46 = OpCompositeExtract %float %params 6
|
||||||
%59 = OpCompositeConstruct %v3float %54 %54 %54
|
%51 = OpCompositeConstruct %v3float %46 %46 %46
|
||||||
%55 = OpFAdd %v3float %53 %59
|
%47 = OpFAdd %v3float %45 %51
|
||||||
%60 = OpFMul %v3float %50 %55
|
%52 = OpFMul %v3float %42 %47
|
||||||
%61 = OpExtInst %v3float %28 FSign %v
|
%53 = OpExtInst %v3float %29 FSign %v
|
||||||
%63 = OpCompositeExtract %float %params 1
|
%55 = OpCompositeExtract %float %params 1
|
||||||
%64 = OpExtInst %v3float %28 FAbs %v
|
%56 = OpExtInst %v3float %29 FAbs %v
|
||||||
%65 = OpVectorTimesScalar %v3float %64 %63
|
%57 = OpVectorTimesScalar %v3float %56 %55
|
||||||
%66 = OpCompositeExtract %float %params 2
|
%58 = OpCompositeExtract %float %params 2
|
||||||
%69 = OpCompositeConstruct %v3float %66 %66 %66
|
%61 = OpCompositeConstruct %v3float %58 %58 %58
|
||||||
%67 = OpFAdd %v3float %65 %69
|
%59 = OpFAdd %v3float %57 %61
|
||||||
%70 = OpCompositeExtract %float %params 0
|
%62 = OpCompositeExtract %float %params 0
|
||||||
%71 = OpCompositeConstruct %v3float %70 %70 %70
|
%63 = OpCompositeConstruct %v3float %62 %62 %62
|
||||||
%62 = OpExtInst %v3float %28 Pow %67 %71
|
%54 = OpExtInst %v3float %29 Pow %59 %63
|
||||||
%72 = OpCompositeExtract %float %params 5
|
%64 = OpCompositeExtract %float %params 5
|
||||||
%75 = OpCompositeConstruct %v3float %72 %72 %72
|
%67 = OpCompositeConstruct %v3float %64 %64 %64
|
||||||
%73 = OpFAdd %v3float %62 %75
|
%65 = OpFAdd %v3float %54 %67
|
||||||
%76 = OpFMul %v3float %61 %73
|
%68 = OpFMul %v3float %53 %65
|
||||||
%77 = OpSelect %v3float %47 %60 %76
|
%69 = OpSelect %v3float %39 %52 %68
|
||||||
OpReturnValue %77
|
OpReturnValue %69
|
||||||
OpFunctionEnd
|
OpFunctionEnd
|
||||||
%textureLoadExternal = OpFunction %v4float None %78
|
%textureLoadExternal = OpFunction %v4float None %70
|
||||||
%plane0 = OpFunctionParameter %3
|
%plane0 = OpFunctionParameter %3
|
||||||
%plane1 = OpFunctionParameter %3
|
%plane1 = OpFunctionParameter %3
|
||||||
%coord = OpFunctionParameter %v2int
|
%coord = OpFunctionParameter %v2int
|
||||||
%params_0 = OpFunctionParameter %ExternalTextureParams
|
%params_0 = OpFunctionParameter %ExternalTextureParams
|
||||||
|
%78 = OpLabel
|
||||||
|
%color = OpVariable %_ptr_Function_v3float Function %50
|
||||||
|
%82 = OpShiftRightArithmetic %v2int %coord %81
|
||||||
|
%84 = OpCompositeExtract %uint %params_0 0
|
||||||
|
%85 = OpIEqual %bool %84 %uint_1
|
||||||
|
OpSelectionMerge %86 None
|
||||||
|
OpBranchConditional %85 %87 %88
|
||||||
|
%87 = OpLabel
|
||||||
|
%91 = OpImageQueryLevels %uint %plane0
|
||||||
|
%92 = OpISub %uint %91 %uint_1
|
||||||
|
%89 = OpExtInst %uint %29 UMin %90 %92
|
||||||
|
%97 = OpImageQuerySizeLod %v2uint %plane0 %89
|
||||||
|
%98 = OpISub %v2uint %97 %81
|
||||||
|
%96 = OpBitcast %v2int %98
|
||||||
|
%94 = OpFunctionCall %v2int %tint_clamp %coord %95 %96
|
||||||
|
%93 = OpImageFetch %v4float %plane0 %94 Lod %89
|
||||||
|
%99 = OpVectorShuffle %v3float %93 %93 0 1 2
|
||||||
|
OpStore %color %99
|
||||||
|
OpBranch %86
|
||||||
|
%88 = OpLabel
|
||||||
|
%101 = OpImageQueryLevels %uint %plane0
|
||||||
|
%102 = OpISub %uint %101 %uint_1
|
||||||
|
%100 = OpExtInst %uint %29 UMin %90 %102
|
||||||
|
%104 = OpImageQueryLevels %uint %plane1
|
||||||
|
%105 = OpISub %uint %104 %uint_1
|
||||||
|
%103 = OpExtInst %uint %29 UMin %90 %105
|
||||||
|
%109 = OpImageQuerySizeLod %v2uint %plane0 %100
|
||||||
|
%110 = OpISub %v2uint %109 %81
|
||||||
|
%108 = OpBitcast %v2int %110
|
||||||
|
%107 = OpFunctionCall %v2int %tint_clamp %coord %95 %108
|
||||||
|
%106 = OpImageFetch %v4float %plane0 %107 Lod %100
|
||||||
|
%111 = OpCompositeExtract %float %106 0
|
||||||
|
%115 = OpImageQuerySizeLod %v2uint %plane1 %103
|
||||||
|
%116 = OpISub %v2uint %115 %81
|
||||||
|
%114 = OpBitcast %v2int %116
|
||||||
|
%113 = OpFunctionCall %v2int %tint_clamp %82 %95 %114
|
||||||
|
%112 = OpImageFetch %v4float %plane1 %113 Lod %103
|
||||||
|
%117 = OpVectorShuffle %v2float %112 %112 0 1
|
||||||
|
%118 = OpCompositeExtract %float %117 0
|
||||||
|
%119 = OpCompositeExtract %float %117 1
|
||||||
|
%121 = OpCompositeConstruct %v4float %111 %118 %119 %float_1
|
||||||
|
%122 = OpCompositeExtract %mat3v4float %params_0 2
|
||||||
|
%123 = OpVectorTimesMatrix %v3float %121 %122
|
||||||
|
OpStore %color %123
|
||||||
|
OpBranch %86
|
||||||
%86 = OpLabel
|
%86 = OpLabel
|
||||||
%color = OpVariable %_ptr_Function_v3float Function %58
|
%124 = OpCompositeExtract %uint %params_0 1
|
||||||
%90 = OpShiftRightArithmetic %v2int %coord %89
|
%125 = OpIEqual %bool %124 %90
|
||||||
%92 = OpCompositeExtract %uint %params_0 0
|
OpSelectionMerge %126 None
|
||||||
%93 = OpIEqual %bool %92 %uint_1
|
OpBranchConditional %125 %127 %126
|
||||||
OpSelectionMerge %94 None
|
%127 = OpLabel
|
||||||
OpBranchConditional %93 %95 %96
|
%129 = OpLoad %v3float %color
|
||||||
%95 = OpLabel
|
%130 = OpCompositeExtract %GammaTransferParams %params_0 3
|
||||||
%107 = OpImageQueryLevels %uint %plane0
|
%128 = OpFunctionCall %v3float %gammaCorrection %129 %130
|
||||||
%108 = OpISub %uint %107 %uint_1
|
OpStore %color %128
|
||||||
%105 = OpBitcast %int %108
|
%131 = OpCompositeExtract %mat3v3float %params_0 5
|
||||||
%103 = OpFunctionCall %int %tint_clamp %104 %104 %105
|
%132 = OpLoad %v3float %color
|
||||||
%102 = OpImageQuerySizeLod %v2uint %plane0 %103
|
%133 = OpMatrixTimesVector %v3float %131 %132
|
||||||
%109 = OpISub %v2uint %102 %89
|
OpStore %color %133
|
||||||
%100 = OpBitcast %v2int %109
|
%135 = OpLoad %v3float %color
|
||||||
%98 = OpFunctionCall %v2int %tint_clamp_1 %coord %99 %100
|
%136 = OpCompositeExtract %GammaTransferParams %params_0 4
|
||||||
%113 = OpImageQueryLevels %uint %plane0
|
%134 = OpFunctionCall %v3float %gammaCorrection %135 %136
|
||||||
%114 = OpISub %uint %113 %uint_1
|
OpStore %color %134
|
||||||
%111 = OpBitcast %int %114
|
OpBranch %126
|
||||||
%110 = OpFunctionCall %int %tint_clamp %104 %104 %111
|
%126 = OpLabel
|
||||||
%97 = OpImageFetch %v4float %plane0 %98 Lod %110
|
%137 = OpLoad %v3float %color
|
||||||
%115 = OpVectorShuffle %v3float %97 %97 0 1 2
|
%138 = OpCompositeExtract %float %137 0
|
||||||
OpStore %color %115
|
%139 = OpCompositeExtract %float %137 1
|
||||||
OpBranch %94
|
%140 = OpCompositeExtract %float %137 2
|
||||||
%96 = OpLabel
|
%141 = OpCompositeConstruct %v4float %138 %139 %140 %float_1
|
||||||
%124 = OpImageQueryLevels %uint %plane0
|
OpReturnValue %141
|
||||||
%125 = OpISub %uint %124 %uint_1
|
|
||||||
%122 = OpBitcast %int %125
|
|
||||||
%121 = OpFunctionCall %int %tint_clamp %104 %104 %122
|
|
||||||
%120 = OpImageQuerySizeLod %v2uint %plane0 %121
|
|
||||||
%126 = OpISub %v2uint %120 %89
|
|
||||||
%118 = OpBitcast %v2int %126
|
|
||||||
%117 = OpFunctionCall %v2int %tint_clamp_1 %coord %99 %118
|
|
||||||
%130 = OpImageQueryLevels %uint %plane0
|
|
||||||
%131 = OpISub %uint %130 %uint_1
|
|
||||||
%128 = OpBitcast %int %131
|
|
||||||
%127 = OpFunctionCall %int %tint_clamp %104 %104 %128
|
|
||||||
%116 = OpImageFetch %v4float %plane0 %117 Lod %127
|
|
||||||
%132 = OpCompositeExtract %float %116 0
|
|
||||||
%141 = OpImageQueryLevels %uint %plane1
|
|
||||||
%142 = OpISub %uint %141 %uint_1
|
|
||||||
%139 = OpBitcast %int %142
|
|
||||||
%138 = OpFunctionCall %int %tint_clamp %104 %104 %139
|
|
||||||
%137 = OpImageQuerySizeLod %v2uint %plane1 %138
|
|
||||||
%143 = OpISub %v2uint %137 %89
|
|
||||||
%135 = OpBitcast %v2int %143
|
|
||||||
%134 = OpFunctionCall %v2int %tint_clamp_1 %90 %99 %135
|
|
||||||
%147 = OpImageQueryLevels %uint %plane1
|
|
||||||
%148 = OpISub %uint %147 %uint_1
|
|
||||||
%145 = OpBitcast %int %148
|
|
||||||
%144 = OpFunctionCall %int %tint_clamp %104 %104 %145
|
|
||||||
%133 = OpImageFetch %v4float %plane1 %134 Lod %144
|
|
||||||
%149 = OpVectorShuffle %v2float %133 %133 0 1
|
|
||||||
%150 = OpCompositeExtract %float %149 0
|
|
||||||
%151 = OpCompositeExtract %float %149 1
|
|
||||||
%153 = OpCompositeConstruct %v4float %132 %150 %151 %float_1
|
|
||||||
%154 = OpCompositeExtract %mat3v4float %params_0 2
|
|
||||||
%155 = OpVectorTimesMatrix %v3float %153 %154
|
|
||||||
OpStore %color %155
|
|
||||||
OpBranch %94
|
|
||||||
%94 = OpLabel
|
|
||||||
%156 = OpCompositeExtract %uint %params_0 1
|
|
||||||
%158 = OpIEqual %bool %156 %157
|
|
||||||
OpSelectionMerge %159 None
|
|
||||||
OpBranchConditional %158 %160 %159
|
|
||||||
%160 = OpLabel
|
|
||||||
%162 = OpLoad %v3float %color
|
|
||||||
%163 = OpCompositeExtract %GammaTransferParams %params_0 3
|
|
||||||
%161 = OpFunctionCall %v3float %gammaCorrection %162 %163
|
|
||||||
OpStore %color %161
|
|
||||||
%164 = OpCompositeExtract %mat3v3float %params_0 5
|
|
||||||
%165 = OpLoad %v3float %color
|
|
||||||
%166 = OpMatrixTimesVector %v3float %164 %165
|
|
||||||
OpStore %color %166
|
|
||||||
%168 = OpLoad %v3float %color
|
|
||||||
%169 = OpCompositeExtract %GammaTransferParams %params_0 4
|
|
||||||
%167 = OpFunctionCall %v3float %gammaCorrection %168 %169
|
|
||||||
OpStore %color %167
|
|
||||||
OpBranch %159
|
|
||||||
%159 = OpLabel
|
|
||||||
%170 = OpLoad %v3float %color
|
|
||||||
%171 = OpCompositeExtract %float %170 0
|
|
||||||
%172 = OpCompositeExtract %float %170 1
|
|
||||||
%173 = OpCompositeExtract %float %170 2
|
|
||||||
%174 = OpCompositeConstruct %v4float %171 %172 %173 %float_1
|
|
||||||
OpReturnValue %174
|
|
||||||
OpFunctionEnd
|
OpFunctionEnd
|
||||||
%conv_ExternalTextureParams = OpFunction %ExternalTextureParams None %175
|
%conv_ExternalTextureParams = OpFunction %ExternalTextureParams None %142
|
||||||
%val = OpFunctionParameter %ExternalTextureParams_std140
|
%val = OpFunctionParameter %ExternalTextureParams_std140
|
||||||
%178 = OpLabel
|
%145 = OpLabel
|
||||||
%179 = OpCompositeExtract %uint %val 0
|
%146 = OpCompositeExtract %uint %val 0
|
||||||
%180 = OpCompositeExtract %uint %val 1
|
%147 = OpCompositeExtract %uint %val 1
|
||||||
%181 = OpCompositeExtract %mat3v4float %val 2
|
%148 = OpCompositeExtract %mat3v4float %val 2
|
||||||
%182 = OpCompositeExtract %GammaTransferParams %val 3
|
%149 = OpCompositeExtract %GammaTransferParams %val 3
|
||||||
%183 = OpCompositeExtract %GammaTransferParams %val 4
|
%150 = OpCompositeExtract %GammaTransferParams %val 4
|
||||||
%184 = OpCompositeExtract %mat3v3float %val 5
|
%151 = OpCompositeExtract %mat3v3float %val 5
|
||||||
%185 = OpCompositeExtract %v2float %val 6
|
%152 = OpCompositeExtract %v2float %val 6
|
||||||
%186 = OpCompositeExtract %v2float %val 7
|
%153 = OpCompositeExtract %v2float %val 7
|
||||||
%187 = OpCompositeExtract %v2float %val 8
|
%154 = OpCompositeExtract %v2float %val 8
|
||||||
%188 = OpCompositeConstruct %mat3v2float %185 %186 %187
|
%155 = OpCompositeConstruct %mat3v2float %152 %153 %154
|
||||||
%189 = OpCompositeConstruct %ExternalTextureParams %179 %180 %181 %182 %183 %184 %188
|
%156 = OpCompositeConstruct %ExternalTextureParams %146 %147 %148 %149 %150 %151 %155
|
||||||
OpReturnValue %189
|
OpReturnValue %156
|
||||||
OpFunctionEnd
|
OpFunctionEnd
|
||||||
%main = OpFunction %void None %190
|
%main = OpFunction %void None %157
|
||||||
%193 = OpLabel
|
%160 = OpLabel
|
||||||
%red = OpVariable %_ptr_Function_v4float Function %206
|
%red = OpVariable %_ptr_Function_v4float Function %173
|
||||||
%green = OpVariable %_ptr_Function_v4float Function %206
|
%green = OpVariable %_ptr_Function_v4float Function %173
|
||||||
%195 = OpLoad %3 %t
|
%162 = OpLoad %3 %t
|
||||||
%196 = OpLoad %3 %ext_tex_plane_1
|
%163 = OpLoad %3 %ext_tex_plane_1
|
||||||
%202 = OpAccessChain %_ptr_Uniform_ExternalTextureParams_std140 %ext_tex_params %uint_0
|
%169 = OpAccessChain %_ptr_Uniform_ExternalTextureParams_std140 %ext_tex_params %uint_0
|
||||||
%203 = OpLoad %ExternalTextureParams_std140 %202
|
%170 = OpLoad %ExternalTextureParams_std140 %169
|
||||||
%199 = OpFunctionCall %ExternalTextureParams %conv_ExternalTextureParams %203
|
%166 = OpFunctionCall %ExternalTextureParams %conv_ExternalTextureParams %170
|
||||||
%194 = OpFunctionCall %v4float %textureLoadExternal %195 %196 %198 %199
|
%161 = OpFunctionCall %v4float %textureLoadExternal %162 %163 %165 %166
|
||||||
OpStore %red %194
|
OpStore %red %161
|
||||||
%208 = OpLoad %19 %outImage
|
%175 = OpLoad %19 %outImage
|
||||||
%213 = OpLoad %19 %outImage
|
%179 = OpLoad %19 %outImage
|
||||||
%212 = OpImageQuerySize %v2uint %213
|
%178 = OpImageQuerySize %v2uint %179
|
||||||
%214 = OpISub %v2uint %212 %89
|
%180 = OpISub %v2uint %178 %81
|
||||||
%210 = OpBitcast %v2int %214
|
%177 = OpBitcast %v2int %180
|
||||||
%209 = OpFunctionCall %v2int %tint_clamp_1 %99 %99 %210
|
%176 = OpFunctionCall %v2int %tint_clamp %95 %95 %177
|
||||||
%215 = OpLoad %v4float %red
|
%181 = OpLoad %v4float %red
|
||||||
OpImageWrite %208 %209 %215
|
OpImageWrite %175 %176 %181
|
||||||
%217 = OpLoad %3 %t
|
%183 = OpLoad %3 %t
|
||||||
%218 = OpLoad %3 %ext_tex_plane_1
|
%184 = OpLoad %3 %ext_tex_plane_1
|
||||||
%223 = OpAccessChain %_ptr_Uniform_ExternalTextureParams_std140 %ext_tex_params %uint_0
|
%189 = OpAccessChain %_ptr_Uniform_ExternalTextureParams_std140 %ext_tex_params %uint_0
|
||||||
%224 = OpLoad %ExternalTextureParams_std140 %223
|
%190 = OpLoad %ExternalTextureParams_std140 %189
|
||||||
%222 = OpFunctionCall %ExternalTextureParams %conv_ExternalTextureParams %224
|
%188 = OpFunctionCall %ExternalTextureParams %conv_ExternalTextureParams %190
|
||||||
%216 = OpFunctionCall %v4float %textureLoadExternal %217 %218 %221 %222
|
%182 = OpFunctionCall %v4float %textureLoadExternal %183 %184 %187 %188
|
||||||
OpStore %green %216
|
OpStore %green %182
|
||||||
%227 = OpLoad %19 %outImage
|
%193 = OpLoad %19 %outImage
|
||||||
%234 = OpLoad %19 %outImage
|
%200 = OpLoad %19 %outImage
|
||||||
%233 = OpImageQuerySize %v2uint %234
|
%199 = OpImageQuerySize %v2uint %200
|
||||||
%235 = OpISub %v2uint %233 %89
|
%201 = OpISub %v2uint %199 %81
|
||||||
%231 = OpBitcast %v2int %235
|
%198 = OpBitcast %v2int %201
|
||||||
%228 = OpFunctionCall %v2int %tint_clamp_1 %230 %99 %231
|
%194 = OpFunctionCall %v2int %tint_clamp %197 %95 %198
|
||||||
%236 = OpLoad %v4float %green
|
%202 = OpLoad %v4float %green
|
||||||
OpImageWrite %227 %228 %236
|
OpImageWrite %193 %194 %202
|
||||||
OpReturn
|
OpReturn
|
||||||
OpFunctionEnd
|
OpFunctionEnd
|
||||||
|
|
Loading…
Reference in New Issue