1 // 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 #ifndef SRC_WRITER_GLSL_GENERATOR_IMPL_H_ 16 #define SRC_WRITER_GLSL_GENERATOR_IMPL_H_ 17 18 #include <string> 19 #include <unordered_map> 20 #include <unordered_set> 21 #include <utility> 22 23 #include "src/ast/assignment_statement.h" 24 #include "src/ast/bitcast_expression.h" 25 #include "src/ast/break_statement.h" 26 #include "src/ast/continue_statement.h" 27 #include "src/ast/discard_statement.h" 28 #include "src/ast/for_loop_statement.h" 29 #include "src/ast/if_statement.h" 30 #include "src/ast/loop_statement.h" 31 #include "src/ast/return_statement.h" 32 #include "src/ast/switch_statement.h" 33 #include "src/ast/unary_op_expression.h" 34 #include "src/program_builder.h" 35 #include "src/scope_stack.h" 36 #include "src/transform/decompose_memory_access.h" 37 #include "src/utils/hash.h" 38 #include "src/writer/text_generator.h" 39 40 namespace tint { 41 42 // Forward declarations 43 namespace sem { 44 class Call; 45 class Intrinsic; 46 class TypeConstructor; 47 class TypeConversion; 48 } // namespace sem 49 50 namespace writer { 51 namespace glsl { 52 53 /// Implementation class for GLSL generator 54 class GeneratorImpl : public TextGenerator { 55 public: 56 /// Constructor 57 /// @param program the program to generate 58 explicit GeneratorImpl(const Program* program); 59 ~GeneratorImpl(); 60 61 /// @returns true on successful generation; false otherwise 62 bool Generate(); 63 64 /// Handles an index accessor expression 65 /// @param out the output of the expression stream 66 /// @param expr the expression to emit 67 /// @returns true if the index accessor was emitted 68 bool EmitIndexAccessor(std::ostream& out, 69 const ast::IndexAccessorExpression* expr); 70 /// Handles an assignment statement 71 /// @param stmt the statement to emit 72 /// @returns true if the statement was emitted successfully 73 bool EmitAssign(const ast::AssignmentStatement* stmt); 74 /// Handles generating a binary expression 75 /// @param out the output of the expression stream 76 /// @param expr the binary expression 77 /// @returns true if the expression was emitted, false otherwise 78 bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr); 79 /// Handles generating a bitcast expression 80 /// @param out the output of the expression stream 81 /// @param expr the expression 82 /// @returns true if the binary expression was emitted 83 bool EmitVectorRelational(std::ostream& out, 84 const ast::BinaryExpression* expr); 85 /// Handles generating a vector relational expression 86 /// @param out the output of the expression stream 87 /// @param expr the expression 88 /// @returns true if the vector relational expression was emitted 89 bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr); 90 /// Emits a list of statements 91 /// @param stmts the statement list 92 /// @returns true if the statements were emitted successfully 93 bool EmitStatements(const ast::StatementList& stmts); 94 /// Emits a list of statements with an indentation 95 /// @param stmts the statement list 96 /// @returns true if the statements were emitted successfully 97 bool EmitStatementsWithIndent(const ast::StatementList& stmts); 98 /// Handles a block statement 99 /// @param stmt the statement to emit 100 /// @returns true if the statement was emitted successfully 101 bool EmitBlock(const ast::BlockStatement* stmt); 102 /// Handles a break statement 103 /// @param stmt the statement to emit 104 /// @returns true if the statement was emitted successfully 105 bool EmitBreak(const ast::BreakStatement* stmt); 106 /// Handles generating a call expression 107 /// @param out the output of the expression stream 108 /// @param expr the call expression 109 /// @returns true if the call expression is emitted 110 bool EmitCall(std::ostream& out, const ast::CallExpression* expr); 111 /// Handles generating a function call expression 112 /// @param out the output of the expression stream 113 /// @param call the call expression 114 /// @param function the function being called 115 /// @returns true if the expression is emitted 116 bool EmitFunctionCall(std::ostream& out, 117 const sem::Call* call, 118 const sem::Function* function); 119 /// Handles generating an intrinsic call expression 120 /// @param out the output of the expression stream 121 /// @param call the call expression 122 /// @param intrinsic the intrinsic being called 123 /// @returns true if the expression is emitted 124 bool EmitIntrinsicCall(std::ostream& out, 125 const sem::Call* call, 126 const sem::Intrinsic* intrinsic); 127 /// Handles generating a type conversion expression 128 /// @param out the output of the expression stream 129 /// @param call the call expression 130 /// @param conv the type conversion 131 /// @returns true if the expression is emitted 132 bool EmitTypeConversion(std::ostream& out, 133 const sem::Call* call, 134 const sem::TypeConversion* conv); 135 /// Handles generating a type constructor expression 136 /// @param out the output of the expression stream 137 /// @param call the call expression 138 /// @param ctor the type constructor 139 /// @returns true if the expression is emitted 140 bool EmitTypeConstructor(std::ostream& out, 141 const sem::Call* call, 142 const sem::TypeConstructor* ctor); 143 /// Handles generating a barrier intrinsic call 144 /// @param out the output of the expression stream 145 /// @param intrinsic the semantic information for the barrier intrinsic 146 /// @returns true if the call expression is emitted 147 bool EmitBarrierCall(std::ostream& out, const sem::Intrinsic* intrinsic); 148 /// Handles generating an atomic intrinsic call for a storage buffer variable 149 /// @param out the output of the expression stream 150 /// @param expr the call expression 151 /// @param intrinsic the atomic intrinsic 152 /// @returns true if the call expression is emitted 153 bool EmitStorageAtomicCall( 154 std::ostream& out, 155 const ast::CallExpression* expr, 156 const transform::DecomposeMemoryAccess::Intrinsic* intrinsic); 157 /// Handles generating an atomic intrinsic call for a workgroup variable 158 /// @param out the output of the expression stream 159 /// @param expr the call expression 160 /// @param intrinsic the semantic information for the atomic intrinsic 161 /// @returns true if the call expression is emitted 162 bool EmitWorkgroupAtomicCall(std::ostream& out, 163 const ast::CallExpression* expr, 164 const sem::Intrinsic* intrinsic); 165 /// Handles generating a call to a texture function (`textureSample`, 166 /// `textureSampleGrad`, etc) 167 /// @param out the output of the expression stream 168 /// @param call the call expression 169 /// @param intrinsic the semantic information for the texture intrinsic 170 /// @returns true if the call expression is emitted 171 bool EmitTextureCall(std::ostream& out, 172 const sem::Call* call, 173 const sem::Intrinsic* intrinsic); 174 /// Handles generating a call to the `select()` intrinsic 175 /// @param out the output of the expression stream 176 /// @param expr the call expression 177 /// @returns true if the call expression is emitted 178 bool EmitSelectCall(std::ostream& out, const ast::CallExpression* expr); 179 /// Handles generating a call to the `dot()` intrinsic 180 /// @param out the output of the expression stream 181 /// @param expr the call expression 182 /// @param intrinsic the semantic information for the intrinsic 183 /// @returns true if the call expression is emitted 184 bool EmitDotCall(std::ostream& out, 185 const ast::CallExpression* expr, 186 const sem::Intrinsic* intrinsic); 187 /// Handles generating a call to the `modf()` intrinsic 188 /// @param out the output of the expression stream 189 /// @param expr the call expression 190 /// @param intrinsic the semantic information for the intrinsic 191 /// @returns true if the call expression is emitted 192 bool EmitModfCall(std::ostream& out, 193 const ast::CallExpression* expr, 194 const sem::Intrinsic* intrinsic); 195 /// Handles generating a call to the `frexp()` intrinsic 196 /// @param out the output of the expression stream 197 /// @param expr the call expression 198 /// @param intrinsic the semantic information for the intrinsic 199 /// @returns true if the call expression is emitted 200 bool EmitFrexpCall(std::ostream& out, 201 const ast::CallExpression* expr, 202 const sem::Intrinsic* intrinsic); 203 /// Handles generating a call to the `isNormal()` intrinsic 204 /// @param out the output of the expression stream 205 /// @param expr the call expression 206 /// @param intrinsic the semantic information for the intrinsic 207 /// @returns true if the call expression is emitted 208 bool EmitIsNormalCall(std::ostream& out, 209 const ast::CallExpression* expr, 210 const sem::Intrinsic* intrinsic); 211 /// Handles generating a call to data packing intrinsic 212 /// @param out the output of the expression stream 213 /// @param expr the call expression 214 /// @param intrinsic the semantic information for the texture intrinsic 215 /// @returns true if the call expression is emitted 216 bool EmitDataPackingCall(std::ostream& out, 217 const ast::CallExpression* expr, 218 const sem::Intrinsic* intrinsic); 219 /// Handles generating a call to data unpacking intrinsic 220 /// @param out the output of the expression stream 221 /// @param expr the call expression 222 /// @param intrinsic the semantic information for the texture intrinsic 223 /// @returns true if the call expression is emitted 224 bool EmitDataUnpackingCall(std::ostream& out, 225 const ast::CallExpression* expr, 226 const sem::Intrinsic* intrinsic); 227 /// Handles a case statement 228 /// @param stmt the statement 229 /// @returns true if the statement was emitted successfully 230 bool EmitCase(const ast::CaseStatement* stmt); 231 /// Handles generating a discard statement 232 /// @param stmt the discard statement 233 /// @returns true if the statement was successfully emitted 234 bool EmitDiscard(const ast::DiscardStatement* stmt); 235 /// Handles a continue statement 236 /// @param stmt the statement to emit 237 /// @returns true if the statement was emitted successfully 238 bool EmitContinue(const ast::ContinueStatement* stmt); 239 /// Handles generate an Expression 240 /// @param out the output of the expression stream 241 /// @param expr the expression 242 /// @returns true if the expression was emitted 243 bool EmitExpression(std::ostream& out, const ast::Expression* expr); 244 /// Handles generating a function 245 /// @param func the function to generate 246 /// @returns true if the function was emitted 247 bool EmitFunction(const ast::Function* func); 248 249 /// Handles emitting a global variable 250 /// @param global the global variable 251 /// @returns true on success 252 bool EmitGlobalVariable(const ast::Variable* global); 253 254 /// Handles emitting a global variable with the uniform storage class 255 /// @param var the global variable 256 /// @returns true on success 257 bool EmitUniformVariable(const sem::Variable* var); 258 259 /// Handles emitting a global variable with the storage storage class 260 /// @param var the global variable 261 /// @returns true on success 262 bool EmitStorageVariable(const sem::Variable* var); 263 264 /// Handles emitting a global variable with the handle storage class 265 /// @param var the global variable 266 /// @returns true on success 267 bool EmitHandleVariable(const sem::Variable* var); 268 269 /// Handles emitting a global variable with the private storage class 270 /// @param var the global variable 271 /// @returns true on success 272 bool EmitPrivateVariable(const sem::Variable* var); 273 274 /// Handles emitting a global variable with the workgroup storage class 275 /// @param var the global variable 276 /// @returns true on success 277 bool EmitWorkgroupVariable(const sem::Variable* var); 278 279 /// Handles emitting the entry point function 280 /// @param func the entry point 281 /// @returns true if the entry point function was emitted 282 bool EmitEntryPointFunction(const ast::Function* func); 283 /// Handles an if statement 284 /// @param stmt the statement to emit 285 /// @returns true if the statement was successfully emitted 286 bool EmitIf(const ast::IfStatement* stmt); 287 /// Handles a literal 288 /// @param out the output stream 289 /// @param lit the literal to emit 290 /// @returns true if the literal was successfully emitted 291 bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit); 292 /// Handles a loop statement 293 /// @param stmt the statement to emit 294 /// @returns true if the statement was emitted 295 bool EmitLoop(const ast::LoopStatement* stmt); 296 /// Handles a for loop statement 297 /// @param stmt the statement to emit 298 /// @returns true if the statement was emitted 299 bool EmitForLoop(const ast::ForLoopStatement* stmt); 300 /// Handles generating an identifier expression 301 /// @param out the output of the expression stream 302 /// @param expr the identifier expression 303 /// @returns true if the identifeir was emitted 304 bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr); 305 /// Handles a member accessor expression 306 /// @param out the output of the expression stream 307 /// @param expr the member accessor expression 308 /// @returns true if the member accessor was emitted 309 bool EmitMemberAccessor(std::ostream& out, 310 const ast::MemberAccessorExpression* expr); 311 /// Handles return statements 312 /// @param stmt the statement to emit 313 /// @returns true if the statement was successfully emitted 314 bool EmitReturn(const ast::ReturnStatement* stmt); 315 /// Handles statement 316 /// @param stmt the statement to emit 317 /// @returns true if the statement was emitted 318 bool EmitStatement(const ast::Statement* stmt); 319 /// Handles generating a switch statement 320 /// @param stmt the statement to emit 321 /// @returns true if the statement was emitted 322 bool EmitSwitch(const ast::SwitchStatement* stmt); 323 /// Handles generating type 324 /// @param out the output stream 325 /// @param type the type to generate 326 /// @param storage_class the storage class of the variable 327 /// @param access the access control type of the variable 328 /// @param name the name of the variable, used for array emission. 329 /// @param name_printed (optional) if not nullptr and an array was printed 330 /// then the boolean is set to true. 331 /// @returns true if the type is emitted 332 bool EmitType(std::ostream& out, 333 const sem::Type* type, 334 ast::StorageClass storage_class, 335 ast::Access access, 336 const std::string& name, 337 bool* name_printed = nullptr); 338 /// Handles generating type and name 339 /// @param out the output stream 340 /// @param type the type to generate 341 /// @param storage_class the storage class of the variable 342 /// @param access the access control type of the variable 343 /// @param name the name to emit 344 /// @returns true if the type is emitted 345 bool EmitTypeAndName(std::ostream& out, 346 const sem::Type* type, 347 ast::StorageClass storage_class, 348 ast::Access access, 349 const std::string& name); 350 /// Handles generating a structure declaration 351 /// @param buffer the text buffer that the type declaration will be written to 352 /// @param ty the struct to generate 353 /// @returns true if the struct is emitted 354 bool EmitStructType(TextBuffer* buffer, const sem::Struct* ty); 355 /// Handles generating the members of a structure 356 /// @param buffer the text buffer that the struct members will be written to 357 /// @param ty the struct to generate 358 /// @returns true if the struct members are emitted 359 bool EmitStructMembers(TextBuffer* buffer, const sem::Struct* ty); 360 /// Handles a unary op expression 361 /// @param out the output of the expression stream 362 /// @param expr the expression to emit 363 /// @returns true if the expression was emitted 364 bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr); 365 /// Emits the zero value for the given type 366 /// @param out the output stream 367 /// @param type the type to emit the value for 368 /// @returns true if the zero value was successfully emitted. 369 bool EmitZeroValue(std::ostream& out, const sem::Type* type); 370 /// Handles generating a variable 371 /// @param var the variable to generate 372 /// @returns true if the variable was emitted 373 bool EmitVariable(const ast::Variable* var); 374 /// Handles generating a program scope constant variable 375 /// @param var the variable to emit 376 /// @returns true if the variable was emitted 377 bool EmitProgramConstVariable(const ast::Variable* var); 378 /// Handles generating a builtin method name 379 /// @param intrinsic the semantic info for the intrinsic 380 /// @returns the name or "" if not valid 381 std::string generate_builtin_name(const sem::Intrinsic* intrinsic); 382 /// Converts a builtin to a gl_ string 383 /// @param builtin the builtin to convert 384 /// @param stage pipeline stage in which this builtin is used 385 /// @returns the string name of the builtin or blank on error 386 const char* builtin_to_string(ast::Builtin builtin, ast::PipelineStage stage); 387 /// Converts a builtin to a sem::Type appropriate for GLSL. 388 /// @param builtin the builtin to convert 389 /// @returns the appropriate semantic type or null on error. 390 sem::Type* builtin_type(ast::Builtin builtin); 391 392 /// Converts interpolation attributes to a GLSL modifiers 393 /// @param type the interpolation type 394 /// @param sampling the interpolation sampling 395 /// @returns the string name of the attribute or blank on error 396 std::string interpolation_to_modifiers( 397 ast::InterpolationType type, 398 ast::InterpolationSampling sampling) const; 399 400 private: 401 enum class VarType { kIn, kOut }; 402 403 struct EntryPointData { 404 std::string struct_name; 405 std::string var_name; 406 }; 407 408 struct DMAIntrinsic { 409 transform::DecomposeMemoryAccess::Intrinsic::Op op; 410 transform::DecomposeMemoryAccess::Intrinsic::DataType type; 411 bool operator==(const DMAIntrinsic& rhs) const { 412 return op == rhs.op && type == rhs.type; 413 } 414 /// Hasher is a std::hash function for DMAIntrinsic 415 struct Hasher { 416 /// @param i the DMAIntrinsic to hash 417 /// @returns the hash of `i` operatorDMAIntrinsic::Hasher418 inline std::size_t operator()(const DMAIntrinsic& i) const { 419 return utils::Hash(i.op, i.type); 420 } 421 }; 422 }; 423 424 /// CallIntrinsicHelper will call the intrinsic helper function, creating it 425 /// if it hasn't been built already. If the intrinsic needs to be built then 426 /// CallIntrinsicHelper will generate the function signature and will call 427 /// `build` to emit the body of the function. 428 /// @param out the output of the expression stream 429 /// @param call the call expression 430 /// @param intrinsic the semantic information for the intrinsic 431 /// @param build a function with the signature: 432 /// `bool(TextBuffer* buffer, const std::vector<std::string>& params)` 433 /// Where: 434 /// `buffer` is the body of the generated function 435 /// `params` is the name of all the generated function parameters 436 /// @returns true if the call expression is emitted 437 template <typename F> 438 bool CallIntrinsicHelper(std::ostream& out, 439 const ast::CallExpression* call, 440 const sem::Intrinsic* intrinsic, 441 F&& build); 442 443 TextBuffer helpers_; // Helper functions emitted at the top of the output 444 std::function<bool()> emit_continuing_; 445 std::unordered_map<DMAIntrinsic, std::string, DMAIntrinsic::Hasher> 446 dma_intrinsics_; 447 std::unordered_map<const sem::Intrinsic*, std::string> intrinsics_; 448 std::unordered_map<const sem::Struct*, std::string> structure_builders_; 449 std::unordered_map<const sem::Vector*, std::string> dynamic_vector_write_; 450 std::unordered_map<const sem::Vector*, std::string> int_dot_funcs_; 451 }; 452 453 } // namespace glsl 454 } // namespace writer 455 } // namespace tint 456 457 #endif // SRC_WRITER_GLSL_GENERATOR_IMPL_H_ 458