blob: 310bc46a5129d30d57ab78f94b39bace6ab776df [file] [log] [blame]
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001// Copyright 2021 The Tint Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "src/tint/transform/multiplanar_external_texture.h"
16
17#include <string>
18#include <vector>
19
20#include "src/tint/ast/function.h"
21#include "src/tint/program_builder.h"
22#include "src/tint/sem/call.h"
23#include "src/tint/sem/function.h"
24#include "src/tint/sem/variable.h"
dan sinclair3cbf3fc2023-01-21 19:16:15 +000025#include "src/tint/type/texture_dimension.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000026
27TINT_INSTANTIATE_TYPEINFO(tint::transform::MultiplanarExternalTexture);
dan sinclair41e4d9a2022-05-01 14:40:55 +000028TINT_INSTANTIATE_TYPEINFO(tint::transform::MultiplanarExternalTexture::NewBindingPoints);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000029
Ben Clayton0ce9ab02022-05-05 20:23:40 +000030using namespace tint::number_suffixes; // NOLINT
31
dan sinclairb5599d32022-04-07 16:55:14 +000032namespace tint::transform {
Ryan Harrisondbc13af2022-02-21 15:19:07 +000033namespace {
34
Ben Claytonc6b38142022-11-03 08:41:19 +000035bool ShouldRun(const Program* program) {
36 for (auto* node : program->ASTNodes().Objects()) {
Ben Clayton971318f2023-02-14 13:52:43 +000037 if (auto* expr = node->As<ast::Expression>()) {
38 if (Is<type::ExternalTexture>(program->TypeOf(expr))) {
Ben Claytonc6b38142022-11-03 08:41:19 +000039 return true;
40 }
41 }
42 }
43 return false;
44}
45
Ben Claytonc4ebf2c2022-09-22 22:59:16 +000046/// This struct stores symbols for new bindings created as a result of transforming a
47/// texture_external instance.
Ryan Harrisondbc13af2022-02-21 15:19:07 +000048struct NewBindingSymbols {
dan sinclair41e4d9a2022-05-01 14:40:55 +000049 Symbol params;
50 Symbol plane_0;
51 Symbol plane_1;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000052};
53} // namespace
54
Ben Claytonc6b38142022-11-03 08:41:19 +000055/// PIMPL state for the transform
Ryan Harrisondbc13af2022-02-21 15:19:07 +000056struct MultiplanarExternalTexture::State {
dan sinclair41e4d9a2022-05-01 14:40:55 +000057 /// The clone context.
58 CloneContext& ctx;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000059
dan sinclair41e4d9a2022-05-01 14:40:55 +000060 /// ProgramBuilder for the context
61 ProgramBuilder& b;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000062
dan sinclair41e4d9a2022-05-01 14:40:55 +000063 /// Destination binding locations for the expanded texture_external provided
64 /// as input into the transform.
65 const NewBindingPoints* new_binding_points;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000066
dan sinclair41e4d9a2022-05-01 14:40:55 +000067 /// Symbol for the GammaTransferParams
68 Symbol gamma_transfer_struct_sym;
Brandon Jones41cbf022022-04-29 21:00:14 +000069
dan sinclair41e4d9a2022-05-01 14:40:55 +000070 /// Symbol for the ExternalTextureParams struct
71 Symbol params_struct_sym;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000072
Ben Claytonda5424b2022-10-24 23:58:53 +000073 /// Symbol for the textureLoadExternal functions
74 utils::Hashmap<const sem::CallTarget*, Symbol, 2> texture_load_external_fns;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000075
dan sinclair41e4d9a2022-05-01 14:40:55 +000076 /// Symbol for the textureSampleExternal function
77 Symbol texture_sample_external_sym;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000078
Ben Claytonc4ebf2c2022-09-22 22:59:16 +000079 /// Symbol for the textureSampleExternalDEPRECATED function
80 Symbol texture_sample_external_deprecated_sym;
81
dan sinclair41e4d9a2022-05-01 14:40:55 +000082 /// Symbol for the gammaCorrection function
83 Symbol gamma_correction_sym;
Brandon Jones41cbf022022-04-29 21:00:14 +000084
Ben Claytonc4ebf2c2022-09-22 22:59:16 +000085 /// Storage for new bindings that have been created corresponding to an original
86 /// texture_external binding.
dan sinclair41e4d9a2022-05-01 14:40:55 +000087 std::unordered_map<const sem::Variable*, NewBindingSymbols> new_binding_symbols;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000088
dan sinclair41e4d9a2022-05-01 14:40:55 +000089 /// Constructor
90 /// @param context the clone
91 /// @param newBindingPoints the input destination binding locations for the
92 /// expanded texture_external
93 State(CloneContext& context, const NewBindingPoints* newBindingPoints)
94 : ctx(context), b(*context.dst), new_binding_points(newBindingPoints) {}
Ryan Harrisondbc13af2022-02-21 15:19:07 +000095
dan sinclair41e4d9a2022-05-01 14:40:55 +000096 /// Processes the module
97 void Process() {
98 auto& sem = ctx.src->Sem();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000099
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000100 // For each texture_external binding, we replace it with a texture_2d<f32> binding and
101 // create two additional bindings (one texture_2d<f32> to represent the secondary plane and
102 // one uniform buffer for the ExternalTextureParams struct).
Ben Claytondcdf66e2022-06-17 12:48:51 +0000103 for (auto* global : ctx.src->AST().GlobalVariables()) {
dan sinclairacdf6e12022-08-24 15:47:25 +0000104 auto* sem_var = sem.Get<sem::GlobalVariable>(global);
dan sinclair4595fb72022-12-08 14:14:10 +0000105 if (!sem_var->Type()->UnwrapRef()->Is<type::ExternalTexture>()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000106 continue;
107 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000108
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000109 // If the attributes are empty, then this must be a texture_external passed as a
110 // function parameter. These variables are transformed elsewhere.
Ben Clayton783b1692022-08-02 17:03:35 +0000111 if (global->attributes.IsEmpty()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000112 continue;
113 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000114
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000115 // If we find a texture_external binding, we know we must emit the ExternalTextureParams
116 // struct.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000117 if (!params_struct_sym.IsValid()) {
118 createExtTexParamsStructs();
119 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000120
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000121 // The binding points for the newly introduced bindings must have been provided to this
122 // transform. We fetch the new binding points by providing the original texture_external
123 // binding points into the passed map.
dan sinclaireebbdef2023-03-08 02:48:42 +0000124 sem::BindingPoint bp = sem_var->BindingPoint();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000125
dan sinclair41e4d9a2022-05-01 14:40:55 +0000126 BindingsMap::const_iterator it = new_binding_points->bindings_map.find(bp);
127 if (it == new_binding_points->bindings_map.end()) {
128 b.Diagnostics().add_error(
129 diag::System::Transform,
130 "missing new binding points for texture_external at binding {" +
131 std::to_string(bp.group) + "," + std::to_string(bp.binding) + "}");
132 continue;
133 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000134
dan sinclair41e4d9a2022-05-01 14:40:55 +0000135 BindingPoints bps = it->second;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000136
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000137 // Symbols for the newly created bindings must be saved so they can be passed as
138 // parameters later. These are placed in a map and keyed by the source symbol associated
139 // with the texture_external binding that corresponds with the new destination bindings.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000140 // NewBindingSymbols new_binding_syms;
141 auto& syms = new_binding_symbols[sem_var];
Ben Clayton651d9e22023-02-09 10:34:14 +0000142 syms.plane_0 = ctx.Clone(global->name->symbol);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000143 syms.plane_1 = b.Symbols().New("ext_tex_plane_1");
dan sinclair3cbf3fc2023-01-21 19:16:15 +0000144 b.GlobalVar(syms.plane_1, b.ty.sampled_texture(type::TextureDimension::k2d, b.ty.f32()),
dan sinclairbe4c9f42022-08-29 21:22:31 +0000145 b.Group(AInt(bps.plane_1.group)), b.Binding(AInt(bps.plane_1.binding)));
dan sinclair41e4d9a2022-05-01 14:40:55 +0000146 syms.params = b.Symbols().New("ext_tex_params");
dan sinclair2a651632023-02-19 04:03:55 +0000147 b.GlobalVar(syms.params, b.ty("ExternalTextureParams"), builtin::AddressSpace::kUniform,
Ben Clayton2117f802023-02-03 14:01:43 +0000148 b.Group(AInt(bps.params.group)), b.Binding(AInt(bps.params.binding)));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000149
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000150 // Replace the original texture_external binding with a texture_2d<f32> binding.
Ben Clayton783b1692022-08-02 17:03:35 +0000151 auto cloned_attributes = ctx.Clone(global->attributes);
dan sinclair6e77b472022-10-20 13:38:28 +0000152 const ast::Expression* cloned_initializer = ctx.Clone(global->initializer);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000153
dan sinclair41e4d9a2022-05-01 14:40:55 +0000154 auto* replacement =
dan sinclair3cbf3fc2023-01-21 19:16:15 +0000155 b.Var(syms.plane_0, b.ty.sampled_texture(type::TextureDimension::k2d, b.ty.f32()),
dan sinclair6e77b472022-10-20 13:38:28 +0000156 cloned_initializer, cloned_attributes);
Ben Claytondcdf66e2022-06-17 12:48:51 +0000157 ctx.Replace(global, replacement);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000158 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000159
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000160 // We must update all the texture_external parameters for user declared functions.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000161 for (auto* fn : ctx.src->AST().Functions()) {
162 for (const ast::Variable* param : fn->params) {
163 if (auto* sem_var = sem.Get(param)) {
dan sinclair4595fb72022-12-08 14:14:10 +0000164 if (!sem_var->Type()->UnwrapRef()->Is<type::ExternalTexture>()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000165 continue;
166 }
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000167 // If we find a texture_external, we must ensure the ExternalTextureParams
168 // struct exists.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000169 if (!params_struct_sym.IsValid()) {
170 createExtTexParamsStructs();
171 }
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000172 // When a texture_external is found, we insert all components the
173 // texture_external into the parameter list. We must also place the new symbols
174 // into the transform state so they can be used when transforming function
175 // calls.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000176 auto& syms = new_binding_symbols[sem_var];
Ben Clayton651d9e22023-02-09 10:34:14 +0000177 syms.plane_0 = ctx.Clone(param->name->symbol);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000178 syms.plane_1 = b.Symbols().New("ext_tex_plane_1");
179 syms.params = b.Symbols().New("ext_tex_params");
180 auto tex2d_f32 = [&] {
dan sinclair3cbf3fc2023-01-21 19:16:15 +0000181 return b.ty.sampled_texture(type::TextureDimension::k2d, b.ty.f32());
dan sinclair41e4d9a2022-05-01 14:40:55 +0000182 };
183 ctx.Replace(param, b.Param(syms.plane_0, tex2d_f32()));
184 ctx.InsertAfter(fn->params, param, b.Param(syms.plane_1, tex2d_f32()));
185 ctx.InsertAfter(fn->params, param,
Ben Clayton2117f802023-02-03 14:01:43 +0000186 b.Param(syms.params, b.ty(params_struct_sym)));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000187 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000188 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000189 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000190
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000191 // Transform the external texture builtin calls into calls to the external texture
192 // functions.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000193 ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::CallExpression* {
Ben Claytone5a67ac2022-05-19 21:50:59 +0000194 auto* call = sem.Get(expr)->UnwrapMaterialize()->As<sem::Call>();
195 auto* builtin = call->Target()->As<sem::Builtin>();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000196
Ben Clayton958a4642022-07-26 07:55:24 +0000197 if (builtin && !builtin->Parameters().IsEmpty() &&
dan sinclair4595fb72022-12-08 14:14:10 +0000198 builtin->Parameters()[0]->Type()->Is<type::ExternalTexture>() &&
dan sinclair9543f742023-03-09 01:20:16 +0000199 builtin->Type() != builtin::Function::kTextureDimensions) {
Ben Clayton2f9a9882022-12-17 02:20:04 +0000200 if (auto* var_user =
Ben Clayton0b4a2f12023-02-05 22:59:40 +0000201 sem.GetVal(expr->args[0])->UnwrapLoad()->As<sem::VariableUser>()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000202 auto it = new_binding_symbols.find(var_user->Variable());
203 if (it == new_binding_symbols.end()) {
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000204 // If valid new binding locations were not provided earlier, we would have
205 // been unable to create these symbols. An error message was emitted
206 // earlier, so just return early to avoid internal compiler errors and
207 // retain a clean error message.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000208 return nullptr;
209 }
210 auto& syms = it->second;
211
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000212 switch (builtin->Type()) {
dan sinclair9543f742023-03-09 01:20:16 +0000213 case builtin::Function::kTextureLoad:
Ben Claytonda5424b2022-10-24 23:58:53 +0000214 return createTextureLoad(call, syms);
dan sinclair9543f742023-03-09 01:20:16 +0000215 case builtin::Function::kTextureSampleBaseClampToEdge:
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000216 return createTextureSampleBaseClampToEdge(expr, syms);
217 default:
218 break;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000219 }
220 }
Ben Claytone5a67ac2022-05-19 21:50:59 +0000221 } else if (call->Target()->Is<sem::Function>()) {
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000222 // The call expression may be to a user-defined function that contains a
223 // texture_external parameter. These need to be expanded out to multiple plane
224 // textures and the texture parameters structure.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000225 for (auto* arg : expr->args) {
Ben Clayton0b4a2f12023-02-05 22:59:40 +0000226 if (auto* var_user = sem.GetVal(arg)->UnwrapLoad()->As<sem::VariableUser>()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000227 // Check if a parameter is a texture_external by trying to find
228 // it in the transform state.
229 auto it = new_binding_symbols.find(var_user->Variable());
230 if (it != new_binding_symbols.end()) {
231 auto& syms = it->second;
232 // When we find a texture_external, we must unpack it into its
233 // components.
234 ctx.Replace(arg, b.Expr(syms.plane_0));
235 ctx.InsertAfter(expr->args, arg, b.Expr(syms.plane_1));
236 ctx.InsertAfter(expr->args, arg, b.Expr(syms.params));
237 }
238 }
239 }
240 }
241
242 return nullptr;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000243 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000244 }
245
dan sinclair41e4d9a2022-05-01 14:40:55 +0000246 /// Creates the parameter structs associated with the transform.
247 void createExtTexParamsStructs() {
248 // Create GammaTransferParams struct.
Ben Clayton783b1692022-08-02 17:03:35 +0000249 utils::Vector gamma_transfer_member_list{
dan sinclair41e4d9a2022-05-01 14:40:55 +0000250 b.Member("G", b.ty.f32()), b.Member("A", b.ty.f32()), b.Member("B", b.ty.f32()),
251 b.Member("C", b.ty.f32()), b.Member("D", b.ty.f32()), b.Member("E", b.ty.f32()),
252 b.Member("F", b.ty.f32()), b.Member("padding", b.ty.u32())};
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000253
dan sinclair41e4d9a2022-05-01 14:40:55 +0000254 gamma_transfer_struct_sym = b.Symbols().New("GammaTransferParams");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000255
dan sinclair41e4d9a2022-05-01 14:40:55 +0000256 b.Structure(gamma_transfer_struct_sym, gamma_transfer_member_list);
257
258 // Create ExternalTextureParams struct.
Ben Clayton783b1692022-08-02 17:03:35 +0000259 utils::Vector ext_tex_params_member_list{
dan sinclair41e4d9a2022-05-01 14:40:55 +0000260 b.Member("numPlanes", b.ty.u32()),
jchen10ef62b582022-06-22 03:14:26 +0000261 b.Member("doYuvToRgbConversionOnly", b.ty.u32()),
Brandon Jones85ceb082022-11-30 21:32:26 +0000262 b.Member("yuvToRgbConversionMatrix", b.ty.mat3x4<f32>()),
Ben Clayton2117f802023-02-03 14:01:43 +0000263 b.Member("gammaDecodeParams", b.ty("GammaTransferParams")),
264 b.Member("gammaEncodeParams", b.ty("GammaTransferParams")),
Brandon Jones85ceb082022-11-30 21:32:26 +0000265 b.Member("gamutConversionMatrix", b.ty.mat3x3<f32>()),
Ben Clayton971318f2023-02-14 13:52:43 +0000266 b.Member("coordTransformationMatrix", b.ty.mat3x2<f32>()),
267 };
dan sinclair41e4d9a2022-05-01 14:40:55 +0000268
269 params_struct_sym = b.Symbols().New("ExternalTextureParams");
270
271 b.Structure(params_struct_sym, ext_tex_params_member_list);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000272 }
273
dan sinclair41e4d9a2022-05-01 14:40:55 +0000274 /// Creates the gammaCorrection function if needed and returns a call
275 /// expression to it.
276 void createGammaCorrectionFn() {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000277 gamma_correction_sym = b.Symbols().New("gammaCorrection");
278
Ben Clayton7164b972022-06-15 10:02:37 +0000279 b.Func(
280 gamma_correction_sym,
Ben Clayton783b1692022-08-02 17:03:35 +0000281 utils::Vector{
Ben Clayton7164b972022-06-15 10:02:37 +0000282 b.Param("v", b.ty.vec3<f32>()),
Ben Clayton2117f802023-02-03 14:01:43 +0000283 b.Param("params", b.ty(gamma_transfer_struct_sym)),
Ben Clayton7164b972022-06-15 10:02:37 +0000284 },
285 b.ty.vec3<f32>(),
Ben Clayton783b1692022-08-02 17:03:35 +0000286 utils::Vector{
Ben Clayton7164b972022-06-15 10:02:37 +0000287 // let cond = abs(v) < vec3(params.D);
Ben Clayton58794ae2022-08-19 17:28:53 +0000288 b.Decl(b.Let("cond", b.LessThan(b.Call("abs", "v"),
289 b.vec3<f32>(b.MemberAccessor("params", "D"))))),
Ben Clayton7164b972022-06-15 10:02:37 +0000290 // let t = sign(v) * ((params.C * abs(v)) + params.F);
Ben Clayton58794ae2022-08-19 17:28:53 +0000291 b.Decl(b.Let("t",
Ben Clayton7164b972022-06-15 10:02:37 +0000292 b.Mul(b.Call("sign", "v"),
293 b.Add(b.Mul(b.MemberAccessor("params", "C"), b.Call("abs", "v")),
294 b.MemberAccessor("params", "F"))))),
295 // let f = (sign(v) * pow(((params.A * abs(v)) + params.B),
296 // vec3(params.G))) + params.E;
Ben Clayton58794ae2022-08-19 17:28:53 +0000297 b.Decl(b.Let("f", b.Mul(b.Call("sign", "v"),
298 b.Add(b.Call("pow",
299 b.Add(b.Mul(b.MemberAccessor("params", "A"),
300 b.Call("abs", "v")),
301 b.MemberAccessor("params", "B")),
302 b.vec3<f32>(b.MemberAccessor("params", "G"))),
303 b.MemberAccessor("params", "E"))))),
Ben Clayton7164b972022-06-15 10:02:37 +0000304 // return select(f, t, cond);
305 b.Return(b.Call("select", "f", "t", "cond")),
306 });
Brandon Jones41cbf022022-04-29 21:00:14 +0000307 }
308
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000309 /// Constructs a StatementList containing all the statements making up the body of the texture
310 /// builtin function.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000311 /// @param call_type determines which function body to generate
312 /// @returns a statement list that makes of the body of the chosen function
dan sinclair9543f742023-03-09 01:20:16 +0000313 auto buildTextureBuiltinBody(builtin::Function call_type) {
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000314 utils::Vector<const ast::Statement*, 16> stmts;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000315 const ast::CallExpression* single_plane_call = nullptr;
316 const ast::CallExpression* plane_0_call = nullptr;
317 const ast::CallExpression* plane_1_call = nullptr;
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000318 switch (call_type) {
dan sinclair9543f742023-03-09 01:20:16 +0000319 case builtin::Function::kTextureSampleBaseClampToEdge:
Ben Claytonbe367b72023-01-04 12:29:56 +0000320 stmts.Push(b.Decl(b.Let(
321 "modifiedCoords", b.Mul(b.MemberAccessor("params", "coordTransformationMatrix"),
322 b.vec3<f32>("coord", 1_a)))));
Brandon Jones85ceb082022-11-30 21:32:26 +0000323
Ben Clayton01ac21c2023-02-07 16:14:25 +0000324 stmts.Push(b.Decl(
325 b.Let("plane0_dims",
326 b.Call(b.ty.vec2<f32>(), b.Call("textureDimensions", "plane0", 0_a)))));
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000327 stmts.Push(
328 b.Decl(b.Let("plane0_half_texel", b.Div(b.vec2<f32>(0.5_a), "plane0_dims"))));
Brandon Jones85ceb082022-11-30 21:32:26 +0000329 stmts.Push(b.Decl(
330 b.Let("plane0_clamped", b.Call("clamp", "modifiedCoords", "plane0_half_texel",
331 b.Sub(1_a, "plane0_half_texel")))));
Ben Clayton01ac21c2023-02-07 16:14:25 +0000332 stmts.Push(b.Decl(
333 b.Let("plane1_dims",
334 b.Call(b.ty.vec2<f32>(), b.Call("textureDimensions", "plane1", 0_a)))));
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000335 stmts.Push(
336 b.Decl(b.Let("plane1_half_texel", b.Div(b.vec2<f32>(0.5_a), "plane1_dims"))));
Brandon Jones85ceb082022-11-30 21:32:26 +0000337 stmts.Push(b.Decl(
338 b.Let("plane1_clamped", b.Call("clamp", "modifiedCoords", "plane1_half_texel",
339 b.Sub(1_a, "plane1_half_texel")))));
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000340
341 // textureSampleLevel(plane0, smp, plane0_clamped, 0.0);
342 single_plane_call =
Ben Claytonda5424b2022-10-24 23:58:53 +0000343 b.Call("textureSampleLevel", "plane0", "smp", "plane0_clamped", 0_a);
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000344 // textureSampleLevel(plane0, smp, plane0_clamped, 0.0);
Ben Claytonda5424b2022-10-24 23:58:53 +0000345 plane_0_call = b.Call("textureSampleLevel", "plane0", "smp", "plane0_clamped", 0_a);
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000346 // textureSampleLevel(plane1, smp, plane1_clamped, 0.0);
Ben Claytonda5424b2022-10-24 23:58:53 +0000347 plane_1_call = b.Call("textureSampleLevel", "plane1", "smp", "plane1_clamped", 0_a);
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000348 break;
dan sinclair9543f742023-03-09 01:20:16 +0000349 case builtin::Function::kTextureLoad:
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000350 // textureLoad(plane0, coord, 0);
Ben Claytonda5424b2022-10-24 23:58:53 +0000351 single_plane_call = b.Call("textureLoad", "plane0", "coord", 0_a);
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000352 // textureLoad(plane0, coord, 0);
Ben Claytonda5424b2022-10-24 23:58:53 +0000353 plane_0_call = b.Call("textureLoad", "plane0", "coord", 0_a);
jchen1039b73302023-02-23 13:03:52 +0000354 // let coord1 = coord >> 1;
355 stmts.Push(b.Decl(b.Let("coord1", b.Shr("coord", b.vec2<u32>(1_a)))));
356 // textureLoad(plane1, coord1, 0);
357 plane_1_call = b.Call("textureLoad", "plane1", "coord1", 0_a);
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000358 break;
359 default:
360 TINT_ICE(Transform, b.Diagnostics()) << "unhandled builtin: " << call_type;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000361 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000362
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000363 // var color: vec3<f32>;
364 stmts.Push(b.Decl(b.Var("color", b.ty.vec3(b.ty.f32()))));
365
366 // if ((params.numPlanes == 1u))
367 stmts.Push(
Ben Claytonda5424b2022-10-24 23:58:53 +0000368 b.If(b.Equal(b.MemberAccessor("params", "numPlanes"), b.Expr(1_a)),
dan sinclair41e4d9a2022-05-01 14:40:55 +0000369 b.Block(
370 // color = textureLoad(plane0, coord, 0).rgb;
371 b.Assign("color", b.MemberAccessor(single_plane_call, "rgb"))),
James Price8aff0ed2022-05-02 14:53:36 +0000372 b.Else(b.Block(
dan sinclair41e4d9a2022-05-01 14:40:55 +0000373 // color = vec4<f32>(plane_0_call.r, plane_1_call.rg, 1.0) *
374 // params.yuvToRgbConversionMatrix;
375 b.Assign("color",
376 b.Mul(b.vec4<f32>(b.MemberAccessor(plane_0_call, "r"),
Ben Claytonda5424b2022-10-24 23:58:53 +0000377 b.MemberAccessor(plane_1_call, "rg"), 1_a),
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000378 b.MemberAccessor("params", "yuvToRgbConversionMatrix")))))));
379
380 // if (params.doYuvToRgbConversionOnly == 0u)
381 stmts.Push(
Ben Claytonda5424b2022-10-24 23:58:53 +0000382 b.If(b.Equal(b.MemberAccessor("params", "doYuvToRgbConversionOnly"), b.Expr(0_a)),
jchen10ef62b582022-06-22 03:14:26 +0000383 b.Block(
384 // color = gammaConversion(color, gammaDecodeParams);
385 b.Assign("color", b.Call("gammaCorrection", "color",
386 b.MemberAccessor("params", "gammaDecodeParams"))),
387 // color = (params.gamutConversionMatrix * color);
388 b.Assign("color",
389 b.Mul(b.MemberAccessor("params", "gamutConversionMatrix"), "color")),
390 // color = gammaConversion(color, gammaEncodeParams);
391 b.Assign("color", b.Call("gammaCorrection", "color",
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000392 b.MemberAccessor("params", "gammaEncodeParams"))))));
393
394 // return vec4<f32>(color, 1.f);
Ben Claytonda5424b2022-10-24 23:58:53 +0000395 stmts.Push(b.Return(b.vec4<f32>("color", 1_a)));
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000396
397 return stmts;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000398 }
399
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000400 /// Creates the textureSampleExternal function if needed and returns a call expression to it.
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000401 /// @param expr the call expression being transformed
402 /// @param syms the expanded symbols to be used in the new call
403 /// @returns a call expression to textureSampleExternal
404 const ast::CallExpression* createTextureSampleBaseClampToEdge(const ast::CallExpression* expr,
405 NewBindingSymbols syms) {
406 const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
407
Ben Clayton884f9522023-01-12 22:52:57 +0000408 if (TINT_UNLIKELY(expr->args.Length() != 3)) {
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000409 TINT_ICE(Transform, b.Diagnostics())
410 << "expected textureSampleBaseClampToEdge call with a "
411 "texture_external to have 3 parameters, found "
412 << expr->args.Length() << " parameters";
413 }
414
415 // TextureSampleExternal calls the gammaCorrection function, so ensure it
416 // exists.
417 if (!gamma_correction_sym.IsValid()) {
418 createGammaCorrectionFn();
419 }
420
421 if (!texture_sample_external_sym.IsValid()) {
422 texture_sample_external_sym = b.Symbols().New("textureSampleExternal");
423
424 // Emit the textureSampleExternal function.
dan sinclair3cbf3fc2023-01-21 19:16:15 +0000425 b.Func(texture_sample_external_sym,
426 utils::Vector{
427 b.Param("plane0",
428 b.ty.sampled_texture(type::TextureDimension::k2d, b.ty.f32())),
429 b.Param("plane1",
430 b.ty.sampled_texture(type::TextureDimension::k2d, b.ty.f32())),
dan sinclair3085e232023-01-23 16:24:12 +0000431 b.Param("smp", b.ty.sampler(type::SamplerKind::kSampler)),
dan sinclair3cbf3fc2023-01-21 19:16:15 +0000432 b.Param("coord", b.ty.vec2(b.ty.f32())),
Ben Clayton2117f802023-02-03 14:01:43 +0000433 b.Param("params", b.ty(params_struct_sym)),
dan sinclair3cbf3fc2023-01-21 19:16:15 +0000434 },
435 b.ty.vec4(b.ty.f32()),
dan sinclair9543f742023-03-09 01:20:16 +0000436 buildTextureBuiltinBody(builtin::Function::kTextureSampleBaseClampToEdge));
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000437 }
438
Ben Clayton999db742023-02-02 15:16:28 +0000439 return b.Call(texture_sample_external_sym, utils::Vector{
440 plane_0_binding_param,
441 b.Expr(syms.plane_1),
442 ctx.Clone(expr->args[1]),
443 ctx.Clone(expr->args[2]),
444 b.Expr(syms.params),
445 });
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000446 }
447
448 /// Creates the textureLoadExternal function if needed and returns a call expression to it.
Ben Claytonda5424b2022-10-24 23:58:53 +0000449 /// @param call the call expression being transformed
dan sinclair41e4d9a2022-05-01 14:40:55 +0000450 /// @param syms the expanded symbols to be used in the new call
451 /// @returns a call expression to textureLoadExternal
Ben Claytonda5424b2022-10-24 23:58:53 +0000452 const ast::CallExpression* createTextureLoad(const sem::Call* call, NewBindingSymbols syms) {
Ben Clayton884f9522023-01-12 22:52:57 +0000453 if (TINT_UNLIKELY(call->Arguments().Length() != 2)) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000454 TINT_ICE(Transform, b.Diagnostics())
Ben Claytonda5424b2022-10-24 23:58:53 +0000455 << "expected textureLoad call with a texture_external to have 2 arguments, found "
456 << call->Arguments().Length() << " arguments";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000457 }
458
Ben Claytonda5424b2022-10-24 23:58:53 +0000459 auto& args = call->Arguments();
460
461 // TextureLoadExternal calls the gammaCorrection function, so ensure it exists.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000462 if (!gamma_correction_sym.IsValid()) {
463 createGammaCorrectionFn();
464 }
465
Ben Claytonda5424b2022-10-24 23:58:53 +0000466 auto texture_load_external_sym = texture_load_external_fns.GetOrCreate(call->Target(), [&] {
467 auto& sig = call->Target()->Signature();
468 auto* coord_ty = sig.Parameter(sem::ParameterUsage::kCoords)->Type();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000469
Ben Claytonda5424b2022-10-24 23:58:53 +0000470 auto name = b.Symbols().New("textureLoadExternal");
471
472 // Emit the textureLoadExternal() function.
dan sinclair3cbf3fc2023-01-21 19:16:15 +0000473 b.Func(name,
474 utils::Vector{
475 b.Param("plane0",
476 b.ty.sampled_texture(type::TextureDimension::k2d, b.ty.f32())),
477 b.Param("plane1",
478 b.ty.sampled_texture(type::TextureDimension::k2d, b.ty.f32())),
479 b.Param("coord", CreateASTTypeFor(ctx, coord_ty)),
Ben Clayton2117f802023-02-03 14:01:43 +0000480 b.Param("params", b.ty(params_struct_sym)),
dan sinclair3cbf3fc2023-01-21 19:16:15 +0000481 },
482 b.ty.vec4(b.ty.f32()), //
dan sinclair9543f742023-03-09 01:20:16 +0000483 buildTextureBuiltinBody(builtin::Function::kTextureLoad));
dan sinclair41e4d9a2022-05-01 14:40:55 +0000484
Ben Claytonda5424b2022-10-24 23:58:53 +0000485 return name;
486 });
487
488 auto plane_0_binding_arg = ctx.Clone(args[0]->Declaration());
489
490 return b.Call(texture_load_external_sym, plane_0_binding_arg, syms.plane_1,
491 ctx.Clone(args[1]->Declaration()), syms.params);
Brandon Jones41cbf022022-04-29 21:00:14 +0000492 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000493};
494
dan sinclair41e4d9a2022-05-01 14:40:55 +0000495MultiplanarExternalTexture::NewBindingPoints::NewBindingPoints(BindingsMap inputBindingsMap)
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000496 : bindings_map(std::move(inputBindingsMap)) {}
dan sinclaireebbdef2023-03-08 02:48:42 +0000497
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000498MultiplanarExternalTexture::NewBindingPoints::~NewBindingPoints() = default;
499
500MultiplanarExternalTexture::MultiplanarExternalTexture() = default;
501MultiplanarExternalTexture::~MultiplanarExternalTexture() = default;
502
Ben Claytonc4ebf2c2022-09-22 22:59:16 +0000503// Within this transform, an instance of a texture_external binding is unpacked into two
504// texture_2d<f32> bindings representing two possible planes of a single texture and a uniform
505// buffer binding representing a struct of parameters. Calls to texture builtins that contain a
506// texture_external parameter will be transformed into a newly generated version of the function,
507// which can perform the desired operation on a single RGBA plane or on separate Y and UV planes.
Ben Claytonc6b38142022-11-03 08:41:19 +0000508Transform::ApplyResult MultiplanarExternalTexture::Apply(const Program* src,
509 const DataMap& inputs,
510 DataMap&) const {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000511 auto* new_binding_points = inputs.Get<NewBindingPoints>();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000512
Ben Claytonc6b38142022-11-03 08:41:19 +0000513 if (!ShouldRun(src)) {
514 return SkipTransform;
515 }
516
517 ProgramBuilder b;
518 CloneContext ctx{&b, src, /* auto_clone_symbols */ true};
dan sinclair41e4d9a2022-05-01 14:40:55 +0000519 if (!new_binding_points) {
Ben Claytonc6b38142022-11-03 08:41:19 +0000520 b.Diagnostics().add_error(diag::System::Transform, "missing new binding point data for " +
521 std::string(TypeInfo().name));
522 return Program(std::move(b));
dan sinclair41e4d9a2022-05-01 14:40:55 +0000523 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000524
dan sinclair41e4d9a2022-05-01 14:40:55 +0000525 State state(ctx, new_binding_points);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000526
dan sinclair41e4d9a2022-05-01 14:40:55 +0000527 state.Process();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000528
dan sinclair41e4d9a2022-05-01 14:40:55 +0000529 ctx.Clone();
Ben Claytonc6b38142022-11-03 08:41:19 +0000530 return Program(std::move(b));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000531}
532
dan sinclairb5599d32022-04-07 16:55:14 +0000533} // namespace tint::transform