1#!/usr/bin/env vpython3 2# 3# [VPYTHON:BEGIN] 4# wheel: < 5# name: "infra/python/wheels/perfect-hash-py2_py3" 6# version: "version:0.2.1" 7# > 8# [VPYTHON:END] 9# 10# Copyright 2018 The ANGLE Project Authors. All rights reserved. 11# Use of this source code is governed by a BSD-style license that can be 12# found in the LICENSE file. 13# 14# gen_builtin_symbols.py: 15# Code generation for the built-in symbol tables. 16import sys 17 18# Conditional import enables getting inputs/outputs with python3 instead of vpython3 19if len(sys.argv) < 2: 20 from perfect_hash import generate_hash, Hash2 21 22from collections import OrderedDict 23import argparse 24import copy 25import hashlib 26import json 27import re 28import os 29import random 30 31template_immutablestring_cpp = """// GENERATED FILE - DO NOT EDIT. 32// Generated by {script_name} using data from {variable_data_source_name} and 33// {function_data_source_name}. 34// 35// Copyright 2020 The ANGLE Project Authors. All rights reserved. 36// Use of this source code is governed by a BSD-style license that can be 37// found in the LICENSE file. 38// 39// ImmutableString_{source_label}autogen.cpp: Wrapper for static or pool allocated char arrays, that are guaranteed to be 40// valid and unchanged for the duration of the compilation. 41// Implements mangledNameHash using perfect hash function from gen_builtin_symbols.py 42 43#include "compiler/translator/ImmutableString.h" 44 45std::ostream &operator<<(std::ostream &os, const sh::ImmutableString &str) 46{{ 47 return os.write(str.data(), str.length()); 48}} 49 50#if defined(_MSC_VER) 51# pragma warning(disable : 4309) // truncation of constant value 52#endif 53 54 55namespace 56{{ 57 58constexpr int mangledkT1[] = {{{mangled_S1}}}; 59constexpr int mangledkT2[] = {{{mangled_S2}}}; 60constexpr int mangledkG[] = {{{mangled_G}}}; 61 62int MangledHashG(const char *key, const int *T) 63{{ 64 int sum = 0; 65 66 for (int i = 0; key[i] != '\\0'; i++) 67 {{ 68 sum += T[i] * key[i]; 69 sum %= {mangled_NG}; 70 }} 71 return mangledkG[sum]; 72}} 73 74int MangledPerfectHash(const char *key) 75{{ 76 if (strlen(key) > {mangled_NS}) 77 return 0; 78 79 return (MangledHashG(key, mangledkT1) + MangledHashG(key, mangledkT2)) % {mangled_NG}; 80}} 81 82constexpr int unmangledkT1[] = {{{unmangled_S1}}}; 83constexpr int unmangledkT2[] = {{{unmangled_S2}}}; 84constexpr int unmangledkG[] = {{{unmangled_G}}}; 85 86int UnmangledHashG(const char *key, const int *T) 87{{ 88 int sum = 0; 89 90 for (int i = 0; key[i] != '\\0'; i++) 91 {{ 92 sum += T[i] * key[i]; 93 sum %= {unmangled_NG}; 94 }} 95 return unmangledkG[sum]; 96}} 97 98int UnmangledPerfectHash(const char *key) 99{{ 100 if (strlen(key) > {unmangled_NS}) 101 return 0; 102 103 return (UnmangledHashG(key, unmangledkT1) + UnmangledHashG(key, unmangledkT2)) % {unmangled_NG}; 104}} 105 106}} 107 108namespace sh 109{{ 110 111template <> 112const size_t ImmutableString::FowlerNollVoHash<4>::kFnvPrime = 16777619u; 113 114template <> 115const size_t ImmutableString::FowlerNollVoHash<4>::kFnvOffsetBasis = 0x811c9dc5u; 116 117template <> 118const size_t ImmutableString::FowlerNollVoHash<8>::kFnvPrime = 119 static_cast<size_t>(1099511628211ull); 120 121template <> 122const size_t ImmutableString::FowlerNollVoHash<8>::kFnvOffsetBasis = 123 static_cast<size_t>(0xcbf29ce484222325ull); 124 125uint32_t ImmutableString::mangledNameHash() const 126{{ 127 return MangledPerfectHash(data()); 128}} 129 130uint32_t ImmutableString::unmangledNameHash() const 131{{ 132 return UnmangledPerfectHash(data()); 133}} 134 135}} // namespace sh 136""" 137 138template_immutablestringtest_cpp = """// GENERATED FILE - DO NOT EDIT. 139// Generated by {script_name} using data from {function_data_source_name}. 140// 141// Copyright 2020 The ANGLE Project Authors. All rights reserved. 142// Use of this source code is governed by a BSD-style license that can be 143// found in the LICENSE file. 144// 145// ImmutableString_test_{source_label}autogen.cpp: 146// Tests for matching script-generated hashes with runtime computed hashes. 147 148#include "compiler/translator/ImmutableString.h" 149#include "gtest/gtest.h" 150 151namespace sh 152{{ 153 154TEST(ImmutableStringTest, ScriptGeneratedHashesMatch) 155{{ 156{script_generated_hash_tests} 157{unmangled_script_generated_hash_tests} 158}} 159 160}} // namespace sh 161""" 162 163# The header file has a "get" function for each variable. They are used in traversers. 164# It also declares id values of built-ins with human readable names, so they can be used to identify built-ins. 165template_builtin_header = """// GENERATED FILE - DO NOT EDIT. 166// Generated by {script_name} using data from {variable_data_source_name} and 167// {function_data_source_name}. 168// 169// Copyright 2020 The ANGLE Project Authors. All rights reserved. 170// Use of this source code is governed by a BSD-style license that can be 171// found in the LICENSE file. 172// 173// BuiltIn_{header_label}autogen.h: 174// Compile-time initialized built-ins. 175 176#ifndef COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_ 177#define COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_ 178 179#include "compiler/translator/SymbolUniqueId.h" 180 181namespace sh 182{{ 183 184class TVariable; 185 186class BuiltInId 187{{ 188public: 189 190{builtin_id_declarations} 191 192}}; // class BuiltInId 193 194namespace BuiltInVariable 195{{ 196 197{get_variable_declarations} 198 199}} // namespace BuiltInVariable 200 201}} // namespace sh 202 203#endif // COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_ 204""" 205 206template_symboltable_header = """// GENERATED FILE - DO NOT EDIT. 207// Generated by {script_name} using data from {variable_data_source_name} and 208// {function_data_source_name}. 209// 210// Copyright 2020 The ANGLE Project Authors. All rights reserved. 211// Use of this source code is governed by a BSD-style license that can be 212// found in the LICENSE file. 213// 214// SymbolTable_autogen.h: 215// Autogenerated member variables of TSymbolTable. 216 217#ifndef COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_ 218#define COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_ 219 220namespace sh 221{{ 222 223class TSymbolTableBase 224{{ 225 public: 226 TSymbolTableBase() = default; 227{declare_member_variables} 228}}; 229 230}} // namespace sh 231 232#endif // COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_ 233""" 234 235# By having the variables defined in a cpp file we ensure that there's just one instance of each of the declared variables. 236template_symboltable_cpp = """// GENERATED FILE - DO NOT EDIT. 237// Generated by {script_name} using data from {variable_data_source_name} and 238// {function_data_source_name}. 239// 240// Copyright 2020 The ANGLE Project Authors. All rights reserved. 241// Use of this source code is governed by a BSD-style license that can be 242// found in the LICENSE file. 243// 244// SymbolTable_{source_label}autogen.cpp: 245// Compile-time initialized built-ins. 246 247#include "compiler/translator/SymbolTable.h" 248 249#include "angle_gl.h" 250#include "compiler/translator/tree_util/BuiltIn.h" 251#include "compiler/translator/ImmutableString.h" 252#include "compiler/translator/StaticType.h" 253#include "compiler/translator/Symbol.h" 254#include "compiler/translator/SymbolTable.h" 255 256namespace sh 257{{ 258using Resources = ShBuiltInResources; 259using TableBase = TSymbolTableBase; 260 261const int TSymbolTable::kLastBuiltInId = {last_builtin_id}; 262 263namespace BuiltInName 264{{ 265 266constexpr const ImmutableString _empty(""); 267{name_declarations} 268 269}} // namespace BuiltInName 270 271// TODO(oetuaho): Would be nice to make this a class instead of a namespace so that we could friend 272// this from TVariable. Now symbol constructors taking an id have to be public even though they're 273// not supposed to be accessible from outside of here. http://anglebug.com/2390 274namespace BuiltInVariable 275{{ 276 277{type_array_sizes_declarations} 278 279{variable_declarations} 280 281{get_variable_definitions} 282 283}} // namespace BuiltInVariable 284 285namespace BuiltInParameters 286{{ 287 288{parameter_declarations} 289 290}} // namespace BuiltInParameters 291 292// TODO(oetuaho): Would be nice to make this a class instead of a namespace so that we could friend 293// this from TFunction. Now symbol constructors taking an id have to be public even though they're 294// not supposed to be accessible from outside of here. http://anglebug.com/2390 295namespace Func 296{{ 297 298{function_declarations} 299 300}} // namespace Func 301 302namespace BuiltInArray 303{{ 304using namespace Func; 305using Rule = SymbolRule; 306 307// Rules used to initialize the mangled name array. 308constexpr SymbolRule kRules[] = {{ 309{mangled_rules} 310}}; 311 312// Flat array of all mangled names. 313constexpr const char *kMangledNames[] = {{ 314{mangled_names_array} 315}}; 316 317// Flat array of offsets from a symbol into the rules table. 318constexpr uint16_t kMangledOffsets[] = {{ 319{mangled_offsets_array} 320}}; 321 322using Ext = TExtension; 323 324// Flat array of all unmangled name identifiers. 325constexpr UnmangledEntry unmangled[] = {{ 326{unmangled_array} 327}}; 328 329}} 330 331void TSymbolTable::initializeBuiltInVariables(sh::GLenum shaderType, 332 ShShaderSpec spec, 333 const ShBuiltInResources &resources) 334{{ 335 const TSourceLoc zeroSourceLoc = {{0, 0, 0, 0}}; 336{init_member_variables} 337}} 338 339namespace 340{{ 341uint16_t GetNextRuleIndex(uint32_t nameHash) 342{{ 343 if (nameHash == {num_mangled_names} - 1) 344 return ArraySize(BuiltInArray::kRules); 345 return BuiltInArray::kMangledOffsets[nameHash + 1]; 346}} 347}} // namespace 348 349const TSymbol *TSymbolTable::findBuiltIn(const ImmutableString &name, 350 int shaderVersion) const 351{{ 352 if (name.length() > {max_mangled_name_length}) 353 return nullptr; 354 355 uint32_t nameHash = name.mangledNameHash(); 356 if (nameHash >= {num_mangled_names}) 357 return nullptr; 358 359 const char *actualName = BuiltInArray::kMangledNames[nameHash]; 360 if (name != actualName) 361 return nullptr; 362 363 uint16_t startIndex = BuiltInArray::kMangledOffsets[nameHash]; 364 uint16_t nextIndex = GetNextRuleIndex(nameHash); 365 366 return FindMangledBuiltIn(mShaderSpec, shaderVersion, mShaderType, mResources, *this, BuiltInArray::kRules, startIndex, nextIndex); 367}} 368 369bool TSymbolTable::isUnmangledBuiltInName(const ImmutableString &name, 370 int shaderVersion, 371 const TExtensionBehavior &extensions) const 372{{ 373 if (name.length() > {max_unmangled_name_length}) 374 return false; 375 376 uint32_t nameHash = name.unmangledNameHash(); 377 if (nameHash >= {num_unmangled_names}) 378 return false; 379 380 return BuiltInArray::unmangled[nameHash].matches(name, mShaderSpec, shaderVersion, mShaderType, extensions); 381}} 382 383}} // namespace sh 384""" 385 386template_operator_header = """// GENERATED FILE - DO NOT EDIT. 387// Generated by {script_name} using data from {function_data_source_name}. 388// 389// Copyright 2021 The ANGLE Project Authors. All rights reserved. 390// Use of this source code is governed by a BSD-style license that can be 391// found in the LICENSE file. 392// 393// Operator_autogen.h: 394// Operators used by the high-level (parse tree) representation. 395 396#ifndef COMPILER_TRANSLATOR_OPERATOR_AUTOGEN_H_ 397#define COMPILER_TRANSLATOR_OPERATOR_AUTOGEN_H_ 398 399#include <stdint.h> 400 401namespace sh 402{{ 403 404enum TOperator : uint16_t 405{{ 406 EOpNull, // if in a node, should only mean a node is still being built 407 408 // Call a function defined in the AST. This might be a user-defined function or a function 409 // inserted by an AST transformation. 410 EOpCallFunctionInAST, 411 412 // Call an internal helper function with a raw implementation - the implementation can't be 413 // subject to AST transformations. Raw functions have a few constraints to keep them compatible 414 // with AST traversers: 415 // * They should not return arrays. 416 // * They should not have out parameters. 417 // 418 // DEPRECATED; DO NOT USE. TODO: remove this. http://anglebug.com/6059 419 // 420 EOpCallInternalRawFunction, 421 422 // 423 // Branch (TIntermBranch) 424 // 425 426 EOpKill, // Fragment only 427 EOpReturn, 428 EOpBreak, 429 EOpContinue, 430 431 // 432 // Constructor (TIntermAggregate) 433 // 434 435 EOpConstruct, 436 437 // 438 // Unary operators with special GLSL syntax (TIntermUnary). 439 // 440 441 EOpNegative, 442 EOpPositive, 443 EOpLogicalNot, 444 EOpBitwiseNot, 445 446 EOpPostIncrement, 447 EOpPostDecrement, 448 EOpPreIncrement, 449 EOpPreDecrement, 450 451 EOpArrayLength, 452 453 // 454 // Binary operators with special GLSL syntax (TIntermBinary). 455 // 456 457 EOpAdd, 458 EOpSub, 459 EOpMul, 460 EOpDiv, 461 EOpIMod, 462 463 EOpEqual, 464 EOpNotEqual, 465 EOpLessThan, 466 EOpGreaterThan, 467 EOpLessThanEqual, 468 EOpGreaterThanEqual, 469 470 EOpComma, 471 472 EOpVectorTimesScalar, 473 EOpVectorTimesMatrix, 474 EOpMatrixTimesVector, 475 EOpMatrixTimesScalar, 476 EOpMatrixTimesMatrix, 477 478 EOpLogicalOr, 479 EOpLogicalXor, 480 EOpLogicalAnd, 481 482 EOpBitShiftLeft, 483 EOpBitShiftRight, 484 485 EOpBitwiseAnd, 486 EOpBitwiseXor, 487 EOpBitwiseOr, 488 489 EOpIndexDirect, 490 EOpIndexIndirect, 491 EOpIndexDirectStruct, 492 EOpIndexDirectInterfaceBlock, 493 494 // 495 // Moves (TIntermBinary) 496 // 497 498 EOpAssign, 499 EOpInitialize, 500 EOpAddAssign, 501 EOpSubAssign, 502 503 EOpMulAssign, 504 EOpVectorTimesMatrixAssign, 505 EOpVectorTimesScalarAssign, 506 EOpMatrixTimesScalarAssign, 507 EOpMatrixTimesMatrixAssign, 508 509 EOpDivAssign, 510 EOpIModAssign, 511 EOpBitShiftLeftAssign, 512 EOpBitShiftRightAssign, 513 EOpBitwiseAndAssign, 514 EOpBitwiseXorAssign, 515 EOpBitwiseOrAssign, 516 517 // Not an op, but a marker for the start of built-in ops. 518 EOpLastNonBuiltIn = EOpBitwiseOrAssign, 519 520 // 521 // Built-in functions mapped to operators (either unary (TIntermUnary) or with multiple 522 // parameters (TIntermAggregate)) 523 // 524 {operator_enum_declarations} 525}}; 526 527// Returns the string corresponding to the operator in GLSL. For built-in functions use the 528// function name directly. 529const char *GetOperatorString(TOperator op); 530 531// Say whether or not a binary or unary operation changes the value of a variable. 532bool IsAssignment(TOperator op); 533 534namespace BuiltInGroup 535{{ 536static inline bool IsBuiltIn(TOperator op) 537{{ 538 return op > EOpLastNonBuiltIn; 539}} 540{is_in_group_definitions} 541}} // namespace BuiltInGroup 542 543}} // namespace sh 544 545#endif // COMPILER_TRANSLATOR_OPERATOR_AUTOGEN_H_ 546 547""" 548 549template_rule = """Rule::Get<{spec}, {version}, {shaders}, {extension}>({symbol_or_var})""" 550 551basic_types_enumeration = [ 552 'Void', 553 'Float', 554 'Double', 555 'Int', 556 'UInt', 557 'Bool', 558 'AtomicCounter', 559 'YuvCscStandardEXT', 560 'Sampler2D', 561 'Sampler3D', 562 'SamplerCube', 563 'Sampler2DArray', 564 'SamplerExternalOES', 565 'SamplerExternal2DY2YEXT', 566 'Sampler2DRect', 567 'Sampler2DMS', 568 'Sampler2DMSArray', 569 'ISampler2D', 570 'ISampler3D', 571 'ISamplerCube', 572 'ISampler2DArray', 573 'ISampler2DMS', 574 'ISampler2DMSArray', 575 'USampler2D', 576 'USampler3D', 577 'USamplerCube', 578 'USampler2DArray', 579 'USampler2DMS', 580 'USampler2DMSArray', 581 'Sampler2DShadow', 582 'SamplerCubeShadow', 583 'Sampler2DArrayShadow', 584 'Sampler1D', 585 'Sampler1DArray', 586 'Sampler1DArrayShadow', 587 'SamplerBuffer', 588 'SamplerCubeArray', 589 'SamplerCubeArrayShadow', 590 'Sampler1DShadow', 591 'Sampler2DRectShadow', 592 'ISampler1D', 593 'ISampler1DArray', 594 'ISampler2DRect', 595 'ISamplerBuffer', 596 'ISamplerCubeArray', 597 'USampler1D', 598 'USampler1DArray', 599 'USampler2DRect', 600 'USamplerBuffer', 601 'USamplerCubeArray', 602 'SamplerVideoWEBGL', 603 'Image2D', 604 'Image3D', 605 'Image2DArray', 606 'ImageCube', 607 'Image1D', 608 'Image1DArray', 609 'Image2DMS', 610 'Image2DMSArray', 611 'ImageCubeArray', 612 'ImageRect', 613 'ImageBuffer', 614 'IImage2D', 615 'IImage3D', 616 'IImage2DArray', 617 'IImageCube', 618 'IImage1D', 619 'IImage1DArray', 620 'IImage2DMS', 621 'IImage2DMSArray', 622 'IImageCubeArray', 623 'IImageRect', 624 'IImageBuffer', 625 'UImage2D', 626 'UImage3D', 627 'UImage2DArray', 628 'UImageCube', 629 'UImage1D', 630 'UImage1DArray', 631 'UImage2DMS', 632 'UImage2DMSArray', 633 'UImageCubeArray', 634 'UImageRect', 635 'UImageBuffer', 636 'PixelLocalANGLE', 637 'IPixelLocalANGLE', 638 'UPixelLocalANGLE', 639 'SubpassInput', 640 'ISubpassInput', 641 'USubpassInput', 642 'SubpassInputMS', 643 'ISubpassInputMS', 644 'USubpassInputMS', 645] 646 647id_counter = 0 648 649 650def set_working_dir(): 651 script_dir = os.path.dirname(os.path.abspath(__file__)) 652 os.chdir(script_dir) 653 654 655def get_basic_mangled_name(basic): 656 index = basic_types_enumeration.index(basic) 657 if index < 26: 658 return '0' + chr(ord('A') + index) 659 if index < 52: 660 return '0' + chr(ord('a') + index - 26) 661 if index < 78: 662 return '1' + chr(ord('A') + index - 52) 663 return '1' + chr(ord('a') + index - 78) 664 665 666essl_levels = [ 667 'ESSL3_2_BUILTINS', 'ESSL3_1_BUILTINS', 'ESSL3_BUILTINS', 'ESSL1_BUILTINS', 'COMMON_BUILTINS', 668 'ESSL_INTERNAL_BACKEND_BUILTINS' 669] 670 671glsl_levels = [ 672 'GLSL4_6_BUILTINS', 'GLSL4_5_BUILTINS', 'GLSL4_4_BUILTINS', 'GLSL4_3_BUILTINS', 673 'GLSL4_2_BUILTINS', 'GLSL4_1_BUILTINS', 'GLSL4_BUILTINS', 'GLSL3_3_BUILTINS', 674 'GLSL1_5_BUILTINS', 'GLSL1_4_BUILTINS', 'GLSL1_3_BUILTINS', 'GLSL1_2_BUILTINS', 675 'COMMON_BUILTINS' 676] 677 678 679def generate_suffix_from_level(level): 680 assert (level[:4] == 'GLSL' or level[:4] == 'ESSL') 681 assert (level[-9:] == '_BUILTINS') 682 683 # Turn XYSLN_M_BUILTINS to XYN_M 684 return level[:2] + level[4:-9] 685 686 687def get_essl_shader_version_for_level(level): 688 if level == None: 689 return '-1' 690 elif level == 'ESSL_INTERNAL_BACKEND_BUILTINS': 691 return 'kESSLInternalBackendBuiltIns' 692 elif level == 'ESSL3_2_BUILTINS': 693 return '320' 694 elif level == 'ESSL3_1_BUILTINS': 695 return '310' 696 elif level == 'ESSL3_BUILTINS': 697 return '300' 698 elif level == 'ESSL1_BUILTINS': 699 return '100' 700 elif level == 'COMMON_BUILTINS': 701 return '0' 702 else: 703 raise Exception('Unsupported symbol table level') 704 705 706def get_glsl_shader_version_for_level(level): 707 if level == None: 708 return '-1' 709 elif level == 'GLSL1_2_BUILTINS': 710 return '120' 711 elif level == 'GLSL1_3_BUILTINS': 712 return '130' 713 elif level == 'GLSL1_4_BUILTINS': 714 return '140' 715 elif level == 'GLSL1_5_BUILTINS': 716 return '150' 717 elif level == 'GLSL3_3_BUILTINS': 718 return '330' 719 elif level == 'GLSL4_BUILTINS': 720 return '400' 721 elif level == 'GLSL4_1_BUILTINS': 722 return '410' 723 elif level == 'GLSL4_2_BUILTINS': 724 return '420' 725 elif level == 'GLSL4_3_BUILTINS': 726 return '430' 727 elif level == 'GLSL4_4_BUILTINS': 728 return '440' 729 elif level == 'GLSL4_5_BUILTINS': 730 return '450' 731 elif level == 'GLSL4_6_BUILTINS': 732 return '460' 733 elif level == 'COMMON_BUILTINS': 734 return '0' 735 else: 736 raise Exception('Unsupported symbol table level') 737 738 739def get_shader_version_for_level(spec, level): 740 if spec == "ESSL": 741 return get_essl_shader_version_for_level(level) 742 else: 743 return get_glsl_shader_version_for_level(level) 744 745 746def get_extension_list(extensions): 747 extension_list = [ext.strip() for ext in extensions.split(',')] 748 extension_string = ', '.join(['TExtension::' + ext for ext in extension_list]) 749 return 'std::array<TExtension, ' + str(len(extension_list)) + 'u>{{' + extension_string + '}}' 750 751 752class GroupedList: 753 """"Class for storing a list of objects grouped by symbol table level and condition.""" 754 755 def __init__(self, hashfn, num_names): 756 self.objs = OrderedDict() 757 self.max_name_length = 0 758 self.hashfn = hashfn 759 self.num_names = num_names 760 self.rule_offset = 0 761 762 def add_entry(self, essl_level, glsl_level, shader_type, name, symbol, essl_extension, 763 glsl_extension, script_generated_hash_tests): 764 if essl_level and essl_level not in essl_levels: 765 raise Exception('Unexpected essl level: ' + str(essl_level)) 766 if glsl_level and glsl_level not in glsl_levels: 767 raise Exception('Unexpected glsl level: ' + str(glsl_level)) 768 if len(name) > self.max_name_length: 769 self.max_name_length = len(name) 770 771 name_hash = mangledNameHash(name, self.hashfn, script_generated_hash_tests, False) 772 if name_hash not in self.objs: 773 self.objs[name_hash] = OrderedDict() 774 775 self.objs[name_hash]['name'] = name 776 777 if essl_extension == 'UNDEFINED' and glsl_extension == 'UNDEFINED': 778 if 'symbol' in self.objs[name_hash] and self.objs[name_hash]['symbol'] != symbol: 779 # Adding a variable that is part of two ESSL extensions that have become core 780 if 'symbol2' not in self.objs[name_hash]: 781 if essl_level: 782 self.objs[name_hash]['essl_level2'] = essl_level 783 if glsl_level: 784 self.objs[name_hash]['glsl_level2'] = glsl_level 785 self.objs[name_hash]['symbol2'] = symbol 786 self.objs[name_hash]['shader_type2'] = shader_type 787 elif 'symbol3' not in self.objs[name_hash]: 788 if essl_level: 789 self.objs[name_hash]['essl_level3'] = essl_level 790 if glsl_level: 791 self.objs[name_hash]['glsl_level3'] = glsl_level 792 self.objs[name_hash]['symbol3'] = symbol 793 self.objs[name_hash]['shader_type3'] = shader_type 794 elif 'symbol4' not in self.objs[name_hash]: 795 if essl_level: 796 self.objs[name_hash]['essl_level4'] = essl_level 797 if glsl_level: 798 self.objs[name_hash]['glsl_level4'] = glsl_level 799 self.objs[name_hash]['symbol4'] = symbol 800 self.objs[name_hash]['shader_type4'] = shader_type 801 else: 802 assert (False) 803 else: 804 if essl_level: 805 self.objs[name_hash]['essl_level'] = essl_level 806 if glsl_level: 807 self.objs[name_hash]['glsl_level'] = glsl_level 808 self.objs[name_hash]['symbol'] = symbol 809 self.objs[name_hash]['shader_type'] = shader_type 810 811 if essl_extension != 'UNDEFINED': 812 if ('essl_ext_symbol' in self.objs[name_hash] and 813 self.objs[name_hash]['essl_ext_symbol'] != symbol): 814 # Adding a variable that is part of two ESSL extensions 815 if 'essl_ext_symbol2' not in self.objs[name_hash]: 816 self.objs[name_hash]['essl_extension2'] = essl_extension 817 self.objs[name_hash]['essl_ext_level2'] = essl_level 818 self.objs[name_hash]['essl_ext_symbol2'] = symbol 819 self.objs[name_hash]['essl_ext_shader_type2'] = shader_type 820 elif 'essl_ext_symbol3' not in self.objs[name_hash]: 821 self.objs[name_hash]['essl_extension3'] = essl_extension 822 self.objs[name_hash]['essl_ext_level3'] = essl_level 823 self.objs[name_hash]['essl_ext_symbol3'] = symbol 824 self.objs[name_hash]['essl_ext_shader_type3'] = shader_type 825 elif 'essl_ext_symbol4' not in self.objs[name_hash]: 826 self.objs[name_hash]['essl_extension4'] = essl_extension 827 self.objs[name_hash]['essl_ext_level4'] = essl_level 828 self.objs[name_hash]['essl_ext_symbol4'] = symbol 829 self.objs[name_hash]['essl_ext_shader_type4'] = shader_type 830 else: 831 assert (False) 832 else: 833 self.objs[name_hash]['essl_extension'] = essl_extension 834 self.objs[name_hash]['essl_ext_level'] = essl_level 835 self.objs[name_hash]['essl_ext_symbol'] = symbol 836 self.objs[name_hash]['essl_ext_shader_type'] = shader_type 837 838 if glsl_extension != 'UNDEFINED': 839 self.objs[name_hash]['glsl_extension'] = glsl_extension 840 self.objs[name_hash]['glsl_ext_level'] = glsl_level 841 self.objs[name_hash]['glsl_ext_symbol'] = symbol 842 self.objs[name_hash]['glsl_ext_shader_type'] = shader_type 843 844 def get_max_name_length(self): 845 return self.max_name_length 846 847 def format_rule(self, rule): 848 return template_rule.format(**rule) 849 850 def format_rules(self, rules): 851 return ", ".join([self.format_rule(rule) for rule in rules]) 852 853 def get_rules(self): 854 return self.rules 855 856 def get_names(self): 857 return self.names 858 859 def get_offsets(self): 860 return self.offsets 861 862 def update_arrays(self, essl_only): 863 864 def add_rule(rules, spec, level, shaders, extension, symbol): 865 var = ("&TableBase::%s" % symbol) if symbol.startswith("m_gl") else None 866 867 extension_list = [] 868 specField = "Spec::%s" % ("ESSL" if spec == "ESSL" else "GLSL") 869 versionField = get_shader_version_for_level(spec, level) 870 shadersField = "Shader::%s" % ("ALL" if shaders == "NONE" else shaders) 871 symbolOrVarField = symbol.replace("Func::", "") if var is None else var 872 if extension != None: 873 extension_list = [ext.strip() for ext in extension.split(',')] 874 for ext in extension_list: 875 rules.append({ 876 "spec": specField, 877 "version": versionField, 878 "shaders": shadersField, 879 "extension": "0" if ext == None else "EXT_INDEX(%s)" % ext, 880 "symbol_or_var": symbolOrVarField 881 }) 882 else: 883 rules.append({ 884 "spec": specField, 885 "version": versionField, 886 "shaders": shadersField, 887 "extension": "0", 888 "symbol_or_var": symbolOrVarField 889 }) 890 891 self.names = [] 892 self.offsets = [] 893 self.rules = [] 894 for hash_val in range(0, self.num_names): 895 if hash_val in self.objs: 896 data = self.objs[hash_val] 897 898 rules = [] 899 900 if "symbol" in data and "essl_level" in data: 901 add_rule(rules, "ESSL", data['essl_level'], data['shader_type'], None, 902 data["symbol"]) 903 904 if "symbol" in data and "glsl_level" in data and not essl_only: 905 add_rule(rules, "GLSL", data['glsl_level'], data['shader_type'], None, 906 data["symbol"]) 907 908 if "symbol2" in data and "essl_level2" in data: 909 add_rule(rules, "ESSL", data['essl_level2'], data['shader_type2'], None, 910 data["symbol2"]) 911 912 if "symbol2" in data and "glsl_level2" in data and not essl_only: 913 add_rule(rules, "GLSL", data['glsl_level2'], data['shader_type2'], None, 914 data["symbol2"]) 915 916 if "symbol3" in data and "essl_level3" in data: 917 add_rule(rules, "ESSL", data['essl_level3'], data['shader_type3'], None, 918 data["symbol3"]) 919 920 if "symbol3" in data and "glsl_level3" in data and not essl_only: 921 add_rule(rules, "GLSL", data['glsl_level3'], data['shader_type3'], None, 922 data["symbol3"]) 923 924 if "symbol4" in data and "essl_level4" in data: 925 add_rule(rules, "ESSL", data['essl_level4'], data['shader_type4'], None, 926 data["symbol4"]) 927 928 if "symbol4" in data and "glsl_level4" in data and not essl_only: 929 add_rule(rules, "GLSL", data['glsl_level4'], data['shader_type4'], None, 930 data["symbol4"]) 931 932 if "essl_ext_symbol" in data: 933 add_rule(rules, "ESSL", data["essl_ext_level"], data["essl_ext_shader_type"], 934 data["essl_extension"], data["essl_ext_symbol"]) 935 936 if "glsl_ext_symbol" in data and not essl_only: 937 add_rule(rules, "GLSL", data["glsl_ext_level"], data["glsl_ext_shader_type"], 938 data["glsl_extension"], data["glsl_ext_symbol"]) 939 940 if "essl_ext_symbol2" in data: 941 add_rule(rules, "ESSL", data["essl_ext_level2"], data["essl_ext_shader_type2"], 942 data["essl_extension2"], data["essl_ext_symbol2"]) 943 944 if "essl_ext_symbol3" in data: 945 add_rule(rules, "ESSL", data["essl_ext_level3"], data["essl_ext_shader_type3"], 946 data["essl_extension3"], data["essl_ext_symbol3"]) 947 948 if "essl_ext_symbol4" in data: 949 add_rule(rules, "ESSL", data["essl_ext_level4"], data["essl_ext_shader_type4"], 950 data["essl_extension4"], data["essl_ext_symbol4"]) 951 952 name = data['name'] 953 name_underscore = name.replace("(", "_") 954 955 self.names.append('"%s"' % name) 956 self.offsets.append("%d, // %s" % (self.rule_offset, name_underscore)) 957 self.rules.append("%s" % self.format_rules(rules)) 958 959 self.rule_offset += len(rules) 960 961 else: 962 self.names.append('""') 963 self.offsets.append('%d, // Empty' % self.rule_offset) 964 965 966class UnmangledGroupedList: 967 """"Class for storing a list of unmangled objects grouped by symbol table level and condition.""" 968 969 def __init__(self, hashfn, num_names): 970 self.objs = OrderedDict() 971 self.max_name_length = 0 972 self.hashfn = hashfn 973 self.num_names = num_names 974 975 def add_entry(self, essl_level, glsl_level, shader_type, name, essl_ext, glsl_ext, 976 essl_extension, glsl_extension, unmangled_script_generated_hash_tests): 977 if essl_level and essl_level not in essl_levels: 978 raise Exception('Unexpected essl level: ' + str(essl_level)) 979 if glsl_level and glsl_level not in glsl_levels: 980 raise Exception('Unexpected glsl level: ' + str(glsl_level)) 981 if len(name) > self.max_name_length: 982 self.max_name_length = len(name) 983 984 name_hash = mangledNameHash(name, self.hashfn, unmangled_script_generated_hash_tests, True) 985 self.objs[name_hash] = OrderedDict() 986 self.objs[name_hash]['name'] = name 987 self.objs[name_hash]['essl_level'] = essl_level 988 self.objs[name_hash]['glsl_level'] = glsl_level 989 self.objs[name_hash]['shader_type'] = shader_type 990 self.objs[name_hash]['essl_ext'] = essl_ext 991 self.objs[name_hash]['glsl_ext'] = glsl_ext 992 self.objs[name_hash]['essl_extension'] = essl_extension 993 self.objs[name_hash]['glsl_extension'] = glsl_extension 994 995 def has_key(self, essl_level, glsl_level, shader_type, name): 996 name_hash = mangledNameHash(name, self.hashfn, None, True, False) 997 if name_hash not in self.objs: 998 return False 999 entry = self.objs[name_hash] 1000 if entry['essl_level'] != essl_level: 1001 return False 1002 if entry['glsl_level'] != glsl_level: 1003 return False 1004 if entry['shader_type'] != shader_type: 1005 return False 1006 return True 1007 1008 def get(self, essl_level, glsl_level, shader_type, name): 1009 if self.has_key(essl_level, glsl_level, shader_type, name): 1010 name_hash = mangledNameHash(name, self.hashfn, None, True, False) 1011 return self.objs[name_hash] 1012 return None 1013 1014 def get_max_name_length(self): 1015 return self.max_name_length 1016 1017 def get_array(self): 1018 code = [] 1019 for hash_val in range(0, self.num_names): 1020 obj = self.objs[hash_val] 1021 essl_level = obj['essl_level'] 1022 glsl_level = obj['glsl_level'] 1023 shader_type = 'Shader::' + obj['shader_type'] if obj[ 1024 'shader_type'] != 'NONE' else 'Shader::ALL' 1025 data = [] 1026 data.append('"{name}"'.format(name=obj['name'])) 1027 essl_extensions = [ext.strip() for ext in obj['essl_extension'].split(',')] 1028 template_extensions = 'std::array<TExtension, {count}>{{{{{extensions}}}}}' 1029 data.append( 1030 template_extensions.format( 1031 count=len(essl_extensions), 1032 extensions=','.join(['Ext::' + ext for ext in essl_extensions]))) 1033 data.append("Ext::" + obj['glsl_extension']) 1034 data.append(get_essl_shader_version_for_level(essl_level)) 1035 data.append(get_glsl_shader_version_for_level(glsl_level)) 1036 data.append(shader_type) 1037 1038 code.append('{%s}' % ', '.join(data)) 1039 return code 1040 1041 1042class TType: 1043 1044 def __init__(self, glsl_header_type): 1045 if isinstance(glsl_header_type, str): 1046 self.data = self.parse_type(glsl_header_type) 1047 else: 1048 self.data = glsl_header_type 1049 self.normalize() 1050 1051 def normalize(self): 1052 # Note that this will set primarySize and secondarySize also on genTypes. In that case they 1053 # are overridden when the specific types are generated. 1054 if 'primarySize' not in self.data: 1055 if ('secondarySize' in self.data): 1056 raise Exception( 1057 'Unexpected secondarySize on type that does not have primarySize set') 1058 self.data['primarySize'] = 1 1059 if 'secondarySize' not in self.data: 1060 self.data['secondarySize'] = 1 1061 if 'precision' not in self.data: 1062 self.data['precision'] = 'Undefined' 1063 if 'qualifier' not in self.data: 1064 self.data['qualifier'] = 'Global' 1065 1066 def has_array_size(self): 1067 return 'arraySize' in self.data 1068 1069 def get_statictype_string(self): 1070 template_type = 'StaticType::Get<Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize}>()' 1071 if self.has_array_size(): 1072 template_type = 'StaticType::GetArray<Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize}, kArraySize{arraySize}, 1>()' 1073 return template_type.format(**self.data) 1074 1075 def get_dynamic_type_string(self): 1076 template_type = 'new TType(Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize}' 1077 if self.has_array_size(): 1078 template_type += ', TVector<unsigned int>{{{arraySize}}}' 1079 template_type += ')' 1080 return template_type.format(**self.data) 1081 1082 def get_mangled_name(self): 1083 mangled_name = '' 1084 1085 size_key = (self.data['secondarySize'] - 1) * 4 + self.data['primarySize'] - 1 1086 if size_key < 10: 1087 mangled_name += chr(ord('0') + size_key) 1088 else: 1089 mangled_name += chr(ord('A') + size_key - 10) 1090 mangled_name += get_basic_mangled_name(self.data['basic']) 1091 if self.has_array_size(): 1092 mangled_name += 'x' + str(self.data['arraySize']) 1093 return mangled_name 1094 1095 def get_human_readable_name(self): 1096 name = self.data['basic'] 1097 if self.has_array_size(): 1098 name = str(self.data['arraySize']) + 'x' + name 1099 name += str(self.data['primarySize']) 1100 if self.data['secondarySize'] > 1: 1101 name += 'x' + str(self.data['secondarySize']) 1102 return name 1103 1104 def is_vector(self): 1105 return self.data['primarySize'] > 1 and self.data['secondarySize'] == 1 1106 1107 def is_matrix(self): 1108 return self.data['secondarySize'] > 1 1109 1110 def get_object_size(self): 1111 return self.data['primarySize'] * self.data['secondarySize'] 1112 1113 def specific_sampler_or_image_or_subpass_type(self, basic_type_prefix): 1114 if 'genType' in self.data and self.data['genType'] == 'sampler_or_image_or_subpass': 1115 type = {} 1116 if 'basic' not in self.data: 1117 type['basic'] = {'': 'Float', 'I': 'Int', 'U': 'UInt'}[basic_type_prefix] 1118 type['primarySize'] = self.data['primarySize'] 1119 else: 1120 type['basic'] = basic_type_prefix + self.data['basic'] 1121 type['primarySize'] = 1 1122 type['precision'] = 'Undefined' 1123 return TType(type) 1124 return self 1125 1126 def specific_type(self, vec_size): 1127 type = {} 1128 if 'genType' in self.data: 1129 type['basic'] = self.data['basic'] 1130 type['precision'] = self.data['precision'] 1131 type['qualifier'] = self.data['qualifier'] 1132 type['primarySize'] = vec_size 1133 type['secondarySize'] = 1 1134 return TType(type) 1135 return self 1136 1137 def parse_type(self, glsl_header_type): 1138 # TODO(http://anglebug.com/3833): handle readonly, writeonly qualifiers 1139 if glsl_header_type.startswith('readonly writeonly '): 1140 type_obj = self.parse_type(glsl_header_type[19:]) 1141 type_obj['qualifier'] = 'Readonly Writeonly' 1142 return type_obj 1143 if glsl_header_type.startswith('readonly '): 1144 type_obj = self.parse_type(glsl_header_type[9:]) 1145 type_obj['qualifier'] = 'Readonly' 1146 return type_obj 1147 if glsl_header_type.startswith('writeonly '): 1148 type_obj = self.parse_type(glsl_header_type[10:]) 1149 type_obj['qualifier'] = 'Writeonly' 1150 return type_obj 1151 if glsl_header_type.startswith('out '): 1152 type_obj = self.parse_type(glsl_header_type[4:]) 1153 type_obj['qualifier'] = 'ParamOut' 1154 return type_obj 1155 if glsl_header_type.startswith('inout '): 1156 type_obj = self.parse_type(glsl_header_type[6:]) 1157 type_obj['qualifier'] = 'ParamInOut' 1158 return type_obj 1159 1160 basic_type_map = { 1161 'float': 'Float', 1162 'int': 'Int', 1163 'uint': 'UInt', 1164 'double': 'Double', 1165 'bool': 'Bool', 1166 'void': 'Void', 1167 'atomic_uint': 'AtomicCounter', 1168 'yuvCscStandardEXT': 'YuvCscStandardEXT' 1169 } 1170 1171 if glsl_header_type in basic_type_map: 1172 return {'basic': basic_type_map[glsl_header_type]} 1173 1174 type_obj = {} 1175 1176 basic_type_prefix_map = { 1177 '': 'Float', 1178 'i': 'Int', 1179 'u': 'UInt', 1180 'd': 'Double', 1181 'b': 'Bool', 1182 'v': 'Void' 1183 } 1184 1185 vec_re = re.compile(r'^([iudb]?)vec([234]?)((\[[234]\])?)$') 1186 vec_match = vec_re.match(glsl_header_type) 1187 if vec_match: 1188 type_obj['basic'] = basic_type_prefix_map[vec_match.group(1)] 1189 if vec_match.group(2) == '': 1190 # Type like "ivec" that represents either ivec2, ivec3 or ivec4 1191 type_obj['genType'] = 'vec' 1192 else: 1193 # vec with specific size 1194 if vec_match.group(3) != '': 1195 # vec array 1196 type_obj['primarySize'] = int(vec_match.group(2)) 1197 type_obj['arraySize'] = int(vec_match.group(3)[1]) 1198 else: 1199 type_obj['primarySize'] = int(vec_match.group(2)) 1200 return type_obj 1201 1202 mat_re = re.compile(r'^mat([234])(x([234]))?$') 1203 mat_match = mat_re.match(glsl_header_type) 1204 if mat_match: 1205 type_obj['basic'] = 'Float' 1206 if len(glsl_header_type) == 4: 1207 mat_size = int(mat_match.group(1)) 1208 type_obj['primarySize'] = mat_size 1209 type_obj['secondarySize'] = mat_size 1210 else: 1211 type_obj['primarySize'] = int(mat_match.group(1)) 1212 type_obj['secondarySize'] = int(mat_match.group(3)) 1213 return type_obj 1214 1215 gen_re = re.compile(r'^gen([IUDB]?)Type$') 1216 gen_match = gen_re.match(glsl_header_type) 1217 if gen_match: 1218 type_obj['basic'] = basic_type_prefix_map[gen_match.group(1).lower()] 1219 type_obj['genType'] = 'yes' 1220 return type_obj 1221 1222 if glsl_header_type.startswith('sampler'): 1223 type_obj['basic'] = glsl_header_type[0].upper() + glsl_header_type[1:] 1224 return type_obj 1225 1226 if glsl_header_type.startswith('gsampler') or \ 1227 glsl_header_type.startswith('gimage') or \ 1228 glsl_header_type.startswith('gpixelLocal') or \ 1229 glsl_header_type.startswith('gsubpassInput'): 1230 type_obj['basic'] = glsl_header_type[1].upper() + glsl_header_type[2:] 1231 type_obj['genType'] = 'sampler_or_image_or_subpass' 1232 return type_obj 1233 1234 if glsl_header_type == 'gvec4': 1235 return {'primarySize': 4, 'genType': 'sampler_or_image_or_subpass'} 1236 if glsl_header_type == 'gvec3': 1237 return {'primarySize': 3, 'genType': 'sampler_or_image_or_subpass'} 1238 1239 if glsl_header_type == 'IMAGE_PARAMS': 1240 return {'genType': 'image_params'} 1241 1242 raise Exception('Unrecognized type: ' + str(glsl_header_type)) 1243 1244 1245class SymbolsData: 1246 1247 def __init__(self): 1248 1249 # Declarations of symbol unique ids 1250 self.builtin_id_declarations = [] 1251 1252 # Declarations of name string variables 1253 self.name_declarations = set() 1254 1255 # Code for testing that script-generated hashes match with runtime computed hashes. 1256 self.script_generated_hash_tests = OrderedDict() 1257 self.unmangled_script_generated_hash_tests = OrderedDict() 1258 1259 1260class VariablesData: 1261 1262 def __init__(self): 1263 1264 # Code for defining TVariables stored as members of TSymbolTable. 1265 self.declare_member_variables = [] 1266 self.init_member_variables = [] 1267 1268 # Declarations of static array sizes if any builtin TVariable is array. 1269 self.type_array_sizes_declarations = set() 1270 1271 # Declarations of builtin TVariables 1272 self.variable_declarations = [] 1273 1274 # Functions for querying the pointer to a specific TVariable. 1275 self.get_variable_declarations = [] 1276 self.get_variable_definitions = [] 1277 1278 1279class FunctionsData: 1280 1281 def __init__(self): 1282 1283 # Declarations of builtin TFunctions 1284 self.function_declarations = [] 1285 1286 # TOperator enum values (and grouping comments) for built-in functions. 1287 self.operator_list = dict() 1288 self.operator_enum_declarations = [] 1289 1290 # Functions for testing whether a builtin belongs in group. 1291 self.is_in_group_definitions = [] 1292 1293 # Declarations of parameter arrays for builtin TFunctions. Map from C++ variable name to the 1294 # full declaration. 1295 self.parameter_declarations = {} 1296 1297 self.defined_function_variants = set() 1298 self.defined_parameter_names = set() 1299 1300 def find_op(self, search_index, direction, limit_for_assertion): 1301 1302 while True: 1303 # Make sure the group is not empty. An "opSuffix" must be used to distinguish between 1304 # built-ins with the same name, but in different groups. 1305 assert (search_index != limit_for_assertion) 1306 1307 line = self.operator_enum_declarations[search_index].lstrip() 1308 if line.startswith('EOp'): 1309 return line[:line.index(',')] 1310 search_index += direction 1311 1312 1313class HashFunction: 1314 1315 def __init__(self, f1, f2, G): 1316 self.f1 = f1 1317 self.f2 = f2 1318 self.G = G 1319 1320 def hash(self, key): 1321 return (self.G[self.f1(key)] + self.G[self.f2(key)]) % len(self.G) 1322 1323 1324def get_parsed_functions(functions_txt_filename, essl_only): 1325 1326 def parse_function_parameters(parameters): 1327 if parameters == '': 1328 return [] 1329 parametersOut = [] 1330 parameters = parameters.split(', ') 1331 for parameter in parameters: 1332 parametersOut.append(TType(parameter.strip())) 1333 return parametersOut 1334 1335 lines = [] 1336 with open(functions_txt_filename) as f: 1337 lines = f.readlines() 1338 lines = [ 1339 line.strip() for line in lines if line.strip() != '' and not line.strip().startswith('//') 1340 ] 1341 1342 fun_re = re.compile(r'^(\w+) (\w+)\((.*)\);$') 1343 1344 parsed_functions = OrderedDict() 1345 group_stack = [] 1346 default_metadata = {} 1347 1348 for line in lines: 1349 if line.startswith('GROUP BEGIN '): 1350 group_rest = line[12:].strip() 1351 group_parts = group_rest.split(' ', 1) 1352 current_group = {'functions': [], 'name': group_parts[0], 'subgroups': {}} 1353 if len(group_parts) > 1: 1354 group_metadata = json.loads(group_parts[1]) 1355 current_group.update(group_metadata) 1356 group_stack.append(current_group) 1357 elif line.startswith('GROUP END '): 1358 group_end_name = line[10:].strip() 1359 current_group = group_stack[-1] 1360 if current_group['name'] != group_end_name: 1361 raise Exception('GROUP END: Unexpected function group name "' + group_end_name + 1362 '" was expecting "' + current_group['name'] + '"') 1363 group_stack.pop() 1364 is_top_level_group = (len(group_stack) == 0) 1365 if is_top_level_group: 1366 if current_group['name'] in parsed_functions: 1367 raise Exception('GROUP END: Duplicate group name "%s"' % current_group['name']) 1368 parsed_functions[current_group['name']] = current_group 1369 default_metadata = {} 1370 else: 1371 super_group = group_stack[-1] 1372 super_group['subgroups'][current_group['name']] = current_group 1373 elif line.startswith('DEFAULT METADATA'): 1374 line_rest = line[16:].strip() 1375 default_metadata = json.loads(line_rest) 1376 else: 1377 fun_match = fun_re.match(line) 1378 if fun_match: 1379 return_type = fun_match.group(1) 1380 name = fun_match.group(2) 1381 parameters = fun_match.group(3) 1382 function_props = { 1383 'name': name, 1384 'returnType': TType(return_type), 1385 'parameters': parse_function_parameters(parameters) 1386 } 1387 function_props.update(default_metadata) 1388 if essl_only: 1389 # Skip GLSL-only functions 1390 if 'essl_level' in function_props: 1391 group_stack[-1]['functions'].append(function_props) 1392 else: 1393 group_stack[-1]['functions'].append(function_props) 1394 else: 1395 raise Exception('Unexpected function input line: ' + line) 1396 1397 return parsed_functions 1398 1399 1400def mangledNameHash(str, hashfn, script_generated_hash_tests, unmangled, save_test=True): 1401 hash = hashfn.hash(str) 1402 if save_test: 1403 confidence_check = '' 1404 if unmangled: 1405 confidence_check = ' ASSERT_EQ(0x{hash}u, ImmutableString("{str}").unmangledNameHash());'.format( 1406 hash=('%08x' % hash), str=str) 1407 else: 1408 confidence_check = ' ASSERT_EQ(0x{hash}u, ImmutableString("{str}").mangledNameHash());'.format( 1409 hash=('%08x' % hash), str=str) 1410 script_generated_hash_tests.update({confidence_check: None}) 1411 return hash 1412 1413 1414def get_function_names(group, mangled_names, unmangled_names): 1415 if 'functions' in group: 1416 for function_props in group['functions']: 1417 function_name = function_props['name'] 1418 unmangled_names.append(function_name) 1419 function_variants = gen_function_variants(function_props) 1420 for function_props in function_variants: 1421 parameters = get_parameters(function_props) 1422 mangled_names.append(get_function_mangled_name(function_name, parameters)) 1423 if 'subgroups' in group: 1424 for subgroup_name, subgroup in group['subgroups'].items(): 1425 get_function_names(subgroup, mangled_names, unmangled_names) 1426 1427 1428def get_variable_names(group, mangled_names): 1429 if 'variables' in group: 1430 for variable_name, props in group['variables'].items(): 1431 mangled_names.append(variable_name) 1432 if 'subgroups' in group: 1433 for subgroup_name, subgroup in group['subgroups'].items(): 1434 get_variable_names(subgroup, mangled_names) 1435 1436 1437def get_suffix(props): 1438 if 'suffix' in props: 1439 return props['suffix'] 1440 return '' 1441 1442 1443def get_essl_extension(props): 1444 if 'essl_extension' in props: 1445 return props['essl_extension'] 1446 return 'UNDEFINED' 1447 1448 1449def get_glsl_extension(props): 1450 if 'glsl_extension' in props: 1451 return props['glsl_extension'] 1452 return 'UNDEFINED' 1453 1454 1455def get_op(name, function_props, group_op_suffix): 1456 return 'EOp' + name[0].upper() + name[1:] + group_op_suffix + function_props.get( 1457 'opSuffix', '') 1458 1459 1460def get_known_to_not_have_side_effects(function_props): 1461 if 'hasSideEffects' in function_props: 1462 has_side_effects = function_props['hasSideEffects'] 1463 if isinstance(has_side_effects, str): 1464 assert has_side_effects in ['true', 1465 'false'], 'Bad side effects value: ' + has_side_effects 1466 has_side_effects = has_side_effects == 'true' 1467 assert isinstance(has_side_effects, bool) 1468 return 'false' if has_side_effects else 'true' 1469 else: 1470 for param in get_parameters(function_props): 1471 if 'qualifier' in param.data and (param.data['qualifier'] == 'ParamOut' or 1472 param.data['qualifier'] == 'ParamInOut'): 1473 return 'false' 1474 return 'true' 1475 1476 1477def get_parameters(function_props): 1478 if 'parameters' in function_props: 1479 return function_props['parameters'] 1480 return [] 1481 1482 1483def get_function_mangled_name(function_name, parameters): 1484 mangled_name = function_name + '(' 1485 for param in parameters: 1486 mangled_name += param.get_mangled_name() 1487 return mangled_name 1488 1489 1490def get_function_human_readable_name(function_name, parameters): 1491 name = function_name 1492 for param in parameters: 1493 name += '_' + param.get_human_readable_name() 1494 return name 1495 1496 1497def get_unique_identifier_name(function_name, parameters): 1498 unique_name = function_name + '_' 1499 for param in parameters: 1500 unique_name += param.get_mangled_name() 1501 return unique_name 1502 1503 1504def get_variable_name_to_store_parameter(param): 1505 unique_name = 'pt' 1506 if 'qualifier' in param.data: 1507 if param.data['qualifier'] == 'ParamOut': 1508 unique_name += '_o_' 1509 if param.data['qualifier'] == 'ParamInOut': 1510 unique_name += '_io_' 1511 unique_name += param.get_mangled_name() 1512 return unique_name 1513 1514 1515def get_variable_name_to_store_parameters(parameters): 1516 if len(parameters) == 0: 1517 return 'empty' 1518 unique_name = 'p' 1519 for param in parameters: 1520 if 'qualifier' in param.data: 1521 if param.data['qualifier'] == 'ParamOut': 1522 unique_name += '_o_' 1523 if param.data['qualifier'] == 'ParamInOut': 1524 unique_name += '_io_' 1525 unique_name += param.get_mangled_name() 1526 return unique_name 1527 1528 1529def define_constexpr_type_array_sizes(template_args, type_array_sizes_declarations): 1530 template_array_sizes_declaration = 'constexpr const unsigned int kArraySize{arraySize}[1] = {{{arraySize}}};' 1531 type_array_sizes_declarations.add(template_array_sizes_declaration.format(**template_args)) 1532 1533 1534def define_constexpr_variable(template_args, variable_declarations): 1535 template_args['extension'] = get_extension_list(template_args['extension']) 1536 template_variable_declaration = 'constexpr const TVariable k{name_with_suffix}(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type});' 1537 1538 variable_declarations.append(template_variable_declaration.format(**template_args)) 1539 1540 1541def gen_function_variants(function_props): 1542 function_variants = [] 1543 parameters = get_parameters(function_props) 1544 function_is_gen_type = False 1545 gen_type = set() 1546 image_params_index = 0 1547 for param in parameters + [function_props['returnType']]: 1548 if 'genType' in param.data: 1549 if param.data['genType'] not in [ 1550 'sampler_or_image_or_subpass', 'vec', 'yes', 'image_params' 1551 ]: 1552 raise Exception( 1553 'Unexpected value of genType "' + str(param.data['genType']) + 1554 '" should be "sampler_or_image_or_subpass", "vec", "yes", or "image_params"') 1555 gen_type.add(param.data['genType']) 1556 if param.data['genType'] == 'image_params': 1557 image_params_index = parameters.index(param) 1558 1559 if len(gen_type) == 0: 1560 function_variants.append(function_props) 1561 return function_variants 1562 1563 # If we have image_params then we're generating variants for 33 separate functions, 1564 # each for a different type of image variable 1565 if 'image_params' in gen_type: 1566 variants = [['gimage2D', 'ivec2'], ['gimage3D', 'ivec3'], ['gimageCube', 'ivec3'], 1567 ['gimageBuffer', 'int'], ['gimage2DArray', 'ivec3'], 1568 ['gimageCubeArray', 'ivec3'], ['gimage1D', 'int'], ['gimage1DArray', 'ivec2'], 1569 ['gimageRect', 'ivec2'], ['gimage2DMS', 'ivec2', 'int'], 1570 ['gimage2DMSArray', 'ivec3', 'int']] 1571 for variant in variants: 1572 image_variant_parameters = [] 1573 for param in parameters: 1574 if parameters.index(param) == image_params_index: 1575 for variant_param in variant: 1576 image_variant_parameters.append(TType(variant_param)) 1577 else: 1578 image_variant_parameters.append(param) 1579 types = ['', 'I', 'U'] 1580 for type in types: 1581 variant_props = function_props.copy() 1582 variant_parameters = [] 1583 for param in image_variant_parameters: 1584 variant_parameters.append( 1585 param.specific_sampler_or_image_or_subpass_type(type)) 1586 variant_props['parameters'] = variant_parameters 1587 variant_props['returnType'] = function_props[ 1588 'returnType'].specific_sampler_or_image_or_subpass_type(type) 1589 function_variants.append(variant_props) 1590 return function_variants 1591 1592 # If we have a gsampler_or_image_or_subpass then we're generating variants for float, int and uint 1593 # samplers. 1594 if 'sampler_or_image_or_subpass' in gen_type: 1595 types = ['', 'I', 'U'] 1596 for type in types: 1597 variant_props = function_props.copy() 1598 variant_parameters = [] 1599 for param in parameters: 1600 variant_parameters.append(param.specific_sampler_or_image_or_subpass_type(type)) 1601 variant_props['parameters'] = variant_parameters 1602 variant_props['returnType'] = function_props[ 1603 'returnType'].specific_sampler_or_image_or_subpass_type(type) 1604 function_variants.append(variant_props) 1605 return function_variants 1606 1607 # If we have a normal gentype then we're generating variants for different sizes of vectors. 1608 sizes = range(1, 5) 1609 if 'vec' in gen_type: 1610 sizes = range(2, 5) 1611 for size in sizes: 1612 variant_props = function_props.copy() 1613 variant_parameters = [] 1614 for param in parameters: 1615 variant_parameters.append(param.specific_type(size)) 1616 variant_props['parameters'] = variant_parameters 1617 variant_props['returnType'] = function_props['returnType'].specific_type(size) 1618 function_variants.append(variant_props) 1619 return function_variants 1620 1621 1622def process_single_function(shader_type, group_name, function_props, symbols, variables, functions, 1623 group_op_suffix, unmangled_function_if_statements, mangled_builtins): 1624 global id_counter 1625 1626 function_name = function_props['name'] 1627 essl_level = function_props['essl_level'] if 'essl_level' in function_props else None 1628 glsl_level = function_props['glsl_level'] if 'glsl_level' in function_props else None 1629 essl_extension = get_essl_extension(function_props) 1630 glsl_extension = get_glsl_extension(function_props) 1631 extension = essl_extension if essl_extension != 'UNDEFINED' else glsl_extension 1632 op = get_op(function_name, function_props, group_op_suffix) 1633 template_args = { 1634 'name': function_name, 1635 'name_with_suffix': function_name + get_suffix(function_props), 1636 'essl_level': essl_level, 1637 'glsl_level': glsl_level, 1638 'essl_extension': essl_extension, 1639 'glsl_extension': glsl_extension, 1640 # This assumes that functions cannot be part of an ESSL and GLSL extension 1641 # Will need to update after adding GLSL extension functions if this is not the case 1642 'extension': essl_extension if essl_extension != 'UNDEFINED' else glsl_extension, 1643 'op': op, 1644 'known_to_not_have_side_effects': get_known_to_not_have_side_effects(function_props) 1645 } 1646 1647 function_variants = gen_function_variants(function_props) 1648 1649 template_name_declaration = 'constexpr const ImmutableString {name_with_suffix}("{name}");' 1650 name_declaration = template_name_declaration.format(**template_args) 1651 if not name_declaration in symbols.name_declarations: 1652 symbols.name_declarations.add(name_declaration) 1653 1654 essl_ext = '{essl_extension}'.format(**template_args) 1655 glsl_ext = '{glsl_extension}'.format(**template_args) 1656 unmangled_builtin_no_shader_type = unmangled_function_if_statements.get( 1657 essl_level, glsl_level, 'NONE', function_name) 1658 if unmangled_builtin_no_shader_type != None and unmangled_builtin_no_shader_type[ 1659 'essl_extension'] == 'UNDEFINED' and unmangled_builtin_no_shader_type[ 1660 'glsl_extension'] == 'UNDEFINED': 1661 # We already have this unmangled name without a shader type nor extension on the same level. 1662 # No need to add a duplicate with a type. 1663 pass 1664 elif (not unmangled_function_if_statements.has_key( 1665 essl_level, glsl_level, shader_type, function_name)) or ( 1666 unmangled_builtin_no_shader_type and 1667 ((essl_extension == 'UNDEFINED' and 1668 unmangled_builtin_no_shader_type['essl_extension'] != 'UNDEFINED') or 1669 (glsl_extension == 'UNDEFINED' and 1670 unmangled_builtin_no_shader_type['glsl_extension'] != 'UNDEFINED'))): 1671 unmangled_function_if_statements.add_entry(essl_level, glsl_level, shader_type, 1672 function_name, essl_ext, glsl_ext, 1673 essl_extension, glsl_extension, 1674 symbols.unmangled_script_generated_hash_tests) 1675 1676 extension_string = get_extension_list(template_args['extension']) 1677 1678 if op not in functions.operator_list: 1679 functions.operator_list[op] = group_name 1680 is_unary = group_name.startswith('Math') and len(get_parameters(function_variants[0])) == 1 1681 assert (not is_unary or 1682 all([len(get_parameters(props)) == 1 for props in function_variants])) 1683 1684 template_operator_enum = ' {op},{is_unary_comment}' 1685 template_args['is_unary_comment'] = ' // Unary' if is_unary else '' 1686 1687 functions.operator_enum_declarations.append(template_operator_enum.format(**template_args)) 1688 else: 1689 # Ensure that built-ins in different groups don't generate the same op. The Is<Group> query 1690 # functions rely on this. 1691 previous_group_name = functions.operator_list[op] 1692 if group_name != previous_group_name: 1693 print('Op ' + op + ' found in group ' + group_name + ' but was previously in group ' + 1694 previous_group_name) 1695 assert (group_name == previous_group_name) 1696 1697 for function_props in function_variants: 1698 template_args['id'] = id_counter 1699 1700 parameters = get_parameters(function_props) 1701 1702 template_args['unique_name'] = get_unique_identifier_name( 1703 template_args['name_with_suffix'], parameters) 1704 template_args['param_count'] = len(parameters) 1705 template_args['return_type'] = function_props['returnType'].get_statictype_string() 1706 template_args['mangled_name'] = get_function_mangled_name(function_name, parameters) 1707 template_args['human_readable_name'] = get_function_human_readable_name( 1708 template_args['name_with_suffix'], parameters) 1709 template_args['mangled_name_length'] = len(template_args['mangled_name']) 1710 1711 symbol = '&Func::{unique_name}'.format(**template_args) 1712 mangled_builtins.add_entry(essl_level, glsl_level, shader_type, 1713 template_args['mangled_name'], symbol, 1714 template_args['essl_extension'], 1715 template_args['glsl_extension'], 1716 symbols.script_generated_hash_tests) 1717 1718 if template_args['unique_name'] in functions.defined_function_variants: 1719 continue 1720 functions.defined_function_variants.add(template_args['unique_name']) 1721 1722 template_builtin_id_declaration = ' static constexpr const TSymbolUniqueId {human_readable_name} = TSymbolUniqueId({id});' 1723 symbols.builtin_id_declarations.append( 1724 template_builtin_id_declaration.format(**template_args)) 1725 1726 parameters_list = [] 1727 for param in parameters: 1728 unique_param_name = get_variable_name_to_store_parameter(param) 1729 param_template_args = { 1730 'name': '_empty', 1731 'name_with_suffix': unique_param_name, 1732 'type': param.get_statictype_string(), 1733 'extension': 'UNDEFINED' 1734 } 1735 if unique_param_name not in functions.defined_parameter_names: 1736 id_counter += 1 1737 param_template_args['id'] = id_counter 1738 template_builtin_id_declaration = ' static constexpr const TSymbolUniqueId {name_with_suffix} = TSymbolUniqueId({id});' 1739 symbols.builtin_id_declarations.append( 1740 template_builtin_id_declaration.format(**param_template_args)) 1741 define_constexpr_variable(param_template_args, variables.variable_declarations) 1742 functions.defined_parameter_names.add(unique_param_name) 1743 if param.has_array_size(): 1744 array_size_template_args = {'arraySize': param.data['arraySize']} 1745 define_constexpr_type_array_sizes(array_size_template_args, 1746 variables.type_array_sizes_declarations) 1747 parameters_list.append( 1748 '&BuiltInVariable::k{name_with_suffix}'.format(**param_template_args)) 1749 1750 template_args['parameters_var_name'] = get_variable_name_to_store_parameters(parameters) 1751 if len(parameters) > 0: 1752 template_args['parameters_list'] = ', '.join(parameters_list) 1753 template_parameter_list_declaration = 'constexpr const TVariable *{parameters_var_name}[{param_count}] = {{ {parameters_list} }};' 1754 functions.parameter_declarations[ 1755 template_args['parameters_var_name']] = template_parameter_list_declaration.format( 1756 **template_args) 1757 else: 1758 template_parameter_list_declaration = 'constexpr const TVariable **{parameters_var_name} = nullptr;' 1759 functions.parameter_declarations[ 1760 template_args['parameters_var_name']] = template_parameter_list_declaration.format( 1761 **template_args) 1762 1763 template_args['extension'] = extension_string 1764 template_function_declaration = 'constexpr const TFunction {unique_name}(BuiltInId::{human_readable_name}, BuiltInName::{name_with_suffix}, {extension}, BuiltInParameters::{parameters_var_name}, {param_count}, {return_type}, {op}, {known_to_not_have_side_effects});' 1765 functions.function_declarations.append( 1766 template_function_declaration.format(**template_args)) 1767 1768 id_counter += 1 1769 1770 1771def process_single_function_group(shader_type, group_name, group, symbols, variables, functions, 1772 group_op_suffix, unmangled_function_if_statements, 1773 mangled_builtins): 1774 1775 if 'functions' not in group: 1776 return 1777 1778 for function_props in group['functions']: 1779 process_single_function(shader_type, group_name, function_props, symbols, variables, 1780 functions, group_op_suffix, unmangled_function_if_statements, 1781 mangled_builtins) 1782 1783 if 'essl_extension_becomes_core_in' in function_props: 1784 assert ('essl_extension' in function_props) 1785 1786 core_props = copy.deepcopy(function_props) 1787 1788 # Adjust the props by updating the level, removing extension and adding suffix 1789 core_level = function_props['essl_extension_becomes_core_in'] 1790 core_props['essl_level'] = core_level 1791 del core_props['essl_extension'] 1792 suffix = core_props['suffix'] if 'suffix' in core_props else '' 1793 suffix += generate_suffix_from_level(core_level) 1794 core_props['suffix'] = suffix 1795 1796 process_single_function(shader_type, group_name, core_props, symbols, variables, 1797 functions, group_op_suffix, unmangled_function_if_statements, 1798 mangled_builtins) 1799 1800 1801def process_function_group(group_name, group, symbols, variables, functions, 1802 parent_group_op_suffix, unmangled_function_if_statements, 1803 mangled_builtins): 1804 1805 functions.operator_enum_declarations.append('') 1806 functions.operator_enum_declarations.append(' // Group ' + group_name) 1807 first_op_index = len(functions.operator_enum_declarations) 1808 1809 shader_type = 'NONE' 1810 if 'shader_type' in group: 1811 shader_type = group['shader_type'] 1812 1813 group_op_suffix = parent_group_op_suffix + group.get('opSuffix', '') 1814 process_single_function_group(shader_type, group_name, group, symbols, variables, functions, 1815 group_op_suffix, unmangled_function_if_statements, 1816 mangled_builtins) 1817 1818 if 'subgroups' in group: 1819 for subgroup_name, subgroup in group['subgroups'].items(): 1820 process_function_group(group_name + subgroup_name, subgroup, symbols, variables, 1821 functions, group_op_suffix, unmangled_function_if_statements, 1822 mangled_builtins) 1823 1824 if 'queryFunction' in group: 1825 last_op_index = len(functions.operator_enum_declarations) - 1 1826 1827 first_op = functions.find_op(first_op_index, +1, last_op_index + 1) 1828 last_op = functions.find_op(last_op_index, -1, first_op_index - 1) 1829 1830 template_args = {'first_op': first_op, 'last_op': last_op, 'group_name': group_name} 1831 template_is_in_group_definition = """static inline bool Is{group_name}(TOperator op) 1832{{ 1833 return op >= {first_op} && op <= {last_op}; 1834}}""" 1835 functions.is_in_group_definitions.append( 1836 template_is_in_group_definition.format(**template_args)) 1837 1838 1839def prune_parameters_arrays(parameter_declarations, function_declarations): 1840 # We can share parameters arrays between functions in case one array is a subarray of another. 1841 parameter_variable_name_replacements = {} 1842 used_param_variable_names = set() 1843 for param_variable_name, param_declaration in sorted( 1844 parameter_declarations.items(), key=lambda item: -len(item[0])): 1845 replaced = False 1846 for used in sorted(used_param_variable_names): 1847 if used.startswith(param_variable_name): 1848 parameter_variable_name_replacements[param_variable_name] = used 1849 replaced = True 1850 break 1851 if not replaced: 1852 used_param_variable_names.add(param_variable_name) 1853 1854 for i in range(len(function_declarations)): 1855 for replaced, replacement in parameter_variable_name_replacements.items(): 1856 function_declarations[i] = function_declarations[i].replace( 1857 'BuiltInParameters::' + replaced + ',', 'BuiltInParameters::' + replacement + ',') 1858 1859 return [ 1860 value for key, value in parameter_declarations.items() if key in used_param_variable_names 1861 ] 1862 1863 1864def process_single_variable(shader_type, variable_name, props, symbols, variables, 1865 mangled_builtins): 1866 global id_counter 1867 1868 essl_level = props['essl_level'] if 'essl_level' in props else None 1869 glsl_level = props['glsl_level'] if 'glsl_level' in props else None 1870 template_args = { 1871 'id': 1872 id_counter, 1873 'name': 1874 variable_name, 1875 'name_with_suffix': 1876 variable_name + get_suffix(props), 1877 'essl_level': 1878 essl_level, 1879 'glsl_level': 1880 glsl_level, 1881 'essl_extension': 1882 get_essl_extension(props), 1883 'glsl_extension': 1884 get_glsl_extension(props), 1885 # This assumes that variables cannot be part of an ESSL and GLSL extension 1886 # Will need to update after adding GLSL extension variables if this is not the case 1887 'extension': 1888 get_essl_extension(props) 1889 if get_essl_extension(props) != 'UNDEFINED' else get_glsl_extension(props), 1890 'class': 1891 'TVariable' 1892 } 1893 1894 template_builtin_id_declaration = ' static constexpr const TSymbolUniqueId {name_with_suffix} = TSymbolUniqueId({id});' 1895 symbols.builtin_id_declarations.append(template_builtin_id_declaration.format(**template_args)) 1896 1897 template_name_declaration = 'constexpr const ImmutableString {name}("{name}");' 1898 symbols.name_declarations.add(template_name_declaration.format(**template_args)) 1899 1900 is_member = True 1901 template_init_variable = '' 1902 1903 extension_string = get_extension_list(template_args['extension']) 1904 1905 if 'type' in props: 1906 if props['type']['basic'] != 'Bool' and 'precision' not in props['type']: 1907 raise Exception('Missing precision for variable ' + variable_name) 1908 template_args['type'] = TType(props['type']).get_statictype_string() 1909 1910 if 'fields' in props: 1911 # Handle struct and interface block definitions. 1912 template_args['class'] = props['class'] 1913 template_args['fields'] = 'fields_{name_with_suffix}'.format(**template_args) 1914 variables.init_member_variables.append( 1915 ' TFieldList *{fields} = new TFieldList();'.format(**template_args)) 1916 for field_name, field_type in props['fields'].items(): 1917 template_args['field_name'] = field_name 1918 template_args['field_type'] = TType(field_type).get_dynamic_type_string() 1919 template_name_declaration = 'constexpr const ImmutableString {field_name}("{field_name}");' 1920 symbols.name_declarations.add(template_name_declaration.format(**template_args)) 1921 template_add_field = ' {fields}->push_back(new TField({field_type}, BuiltInName::{field_name}, zeroSourceLoc, SymbolType::BuiltIn));' 1922 variables.init_member_variables.append(template_add_field.format(**template_args)) 1923 template_args['extension'] = extension_string 1924 template_init_temp_variable = ' {class} *{name_with_suffix} = new {class}(BuiltInId::{name_with_suffix}, BuiltInName::{name}, {extension}, {fields});' 1925 variables.init_member_variables.append(template_init_temp_variable.format(**template_args)) 1926 if 'private' in props and props['private']: 1927 is_member = False 1928 else: 1929 template_init_variable = ' m_{name_with_suffix} = {name_with_suffix};' 1930 1931 elif 'initDynamicType' in props: 1932 # Handle variables whose type can't be expressed as TStaticType 1933 # (type is a struct or has variable array size for example). 1934 template_args['type_name'] = 'type_{name_with_suffix}'.format(**template_args) 1935 template_args['type'] = template_args['type_name'] 1936 template_args['ext_or_core_suffix'] = '' 1937 if 'essl_extension_becomes_core_in' in props and 'essl_extension' not in props: 1938 template_args['ext_or_core_suffix'] = generate_suffix_from_level(props['essl_level']) 1939 template_args['initDynamicType'] = props['initDynamicType'].format(**template_args) 1940 template_args['extension'] = extension_string 1941 template_init_variable = """ {initDynamicType} 1942{type_name}->realize(); 1943m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type});""" 1944 1945 elif 'value' in props: 1946 # Handle variables with constant value, such as gl_MaxDrawBuffers. 1947 if props['value'] != 'resources': 1948 raise Exception('Unrecognized value source in variable properties: ' + 1949 str(props['value'])) 1950 resources_key = variable_name[3:] 1951 if 'valueKey' in props: 1952 resources_key = props['valueKey'] 1953 template_args['value'] = 'resources.' + resources_key 1954 template_args['object_size'] = TType(props['type']).get_object_size() 1955 template_args['extension'] = extension_string 1956 template_init_variable = """ m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type}); 1957{{ 1958 TConstantUnion *unionArray = new TConstantUnion[{object_size}]; 1959 unionArray[0].setIConst({value}); 1960 static_cast<TVariable *>(m_{name_with_suffix})->shareConstPointer(unionArray); 1961}}""" 1962 if template_args['object_size'] > 1: 1963 template_init_variable = """ m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type}); 1964{{ 1965 TConstantUnion *unionArray = new TConstantUnion[{object_size}]; 1966 for (size_t index = 0u; index < {object_size}; ++index) 1967 {{ 1968 unionArray[index].setIConst({value}[index]); 1969 }} 1970 static_cast<TVariable *>(m_{name_with_suffix})->shareConstPointer(unionArray); 1971}}""" 1972 1973 else: 1974 # Handle variables that can be stored as constexpr TVariable like 1975 # gl_Position, gl_FragColor etc. 1976 define_constexpr_variable(template_args, variables.variable_declarations) 1977 is_member = False 1978 1979 template_get_variable_declaration = 'const TVariable *{name_with_suffix}();' 1980 variables.get_variable_declarations.append( 1981 template_get_variable_declaration.format(**template_args)) 1982 1983 template_get_variable_definition = """const TVariable *{name_with_suffix}() 1984{{ 1985return &k{name_with_suffix}; 1986}} 1987""" 1988 variables.get_variable_definitions.append( 1989 template_get_variable_definition.format(**template_args)) 1990 1991 if essl_level != 'GLSL_BUILTINS': 1992 obj = '&BuiltInVariable::k{name_with_suffix}'.format(**template_args) 1993 # TODO(http://anglebug.com/3835): Add GLSL level once GLSL built-in vars are added 1994 mangled_builtins.add_entry(essl_level, 'COMMON_BUILTINS', shader_type, 1995 template_args['name'], obj, template_args['essl_extension'], 1996 template_args['glsl_extension'], 1997 symbols.script_generated_hash_tests) 1998 1999 if is_member: 2000 variables.init_member_variables.append(template_init_variable.format(**template_args)) 2001 2002 template_declare_member_variable = 'TSymbol *m_{name_with_suffix} = nullptr;' 2003 variables.declare_member_variables.append( 2004 template_declare_member_variable.format(**template_args)) 2005 2006 obj = 'm_{name_with_suffix}'.format(**template_args) 2007 2008 # TODO(http://anglebug.com/3835): Add GLSL level once GLSL built-in vars are added 2009 mangled_builtins.add_entry(essl_level, 'COMMON_BUILTINS', shader_type, 2010 template_args['name'], obj, template_args['essl_extension'], 2011 template_args['glsl_extension'], 2012 symbols.script_generated_hash_tests) 2013 2014 id_counter += 1 2015 2016 2017def process_single_variable_group(shader_type, group, symbols, variables, mangled_builtins): 2018 global id_counter 2019 if 'variables' not in group: 2020 return 2021 for variable_name, props in group['variables'].items(): 2022 process_single_variable(shader_type, variable_name, props, symbols, variables, 2023 mangled_builtins) 2024 2025 if 'essl_extension_becomes_core_in' in props: 2026 assert ('essl_extension' in props) 2027 2028 core_props = copy.deepcopy(props) 2029 2030 # Adjust the props by updating the level, removing extension and adding suffix 2031 core_level = props['essl_extension_becomes_core_in'] 2032 core_props['essl_level'] = core_level 2033 del core_props['essl_extension'] 2034 suffix = core_props['suffix'] if 'suffix' in core_props else '' 2035 suffix += generate_suffix_from_level(core_level) 2036 core_props['suffix'] = suffix 2037 process_single_variable(shader_type, variable_name, core_props, symbols, variables, 2038 mangled_builtins) 2039 2040 2041def process_variable_group(shader_type, group_name, group, symbols, variables, mangled_builtins): 2042 global id_counter 2043 2044 if 'shader_type' in group: 2045 shader_type = group['shader_type'] 2046 2047 process_single_variable_group(shader_type, group, symbols, variables, mangled_builtins) 2048 2049 if 'subgroups' in group: 2050 for subgroup_name, subgroup in group['subgroups'].items(): 2051 process_variable_group(shader_type, subgroup_name, subgroup, symbols, variables, 2052 mangled_builtins) 2053 2054 2055def generate_files(essl_only, args, functions_txt_filename, variables_json_filename, 2056 immutablestring_cpp_filename, immutablestringtest_cpp_filename, 2057 builtin_header_filename, symboltable_cpp_filename, operator_header_filename, 2058 symboltable_header_filename): 2059 2060 symbols = SymbolsData() 2061 variables = VariablesData() 2062 functions = FunctionsData() 2063 2064 parsed_functions = get_parsed_functions(functions_txt_filename, essl_only) 2065 2066 if args.dump_intermediate_json: 2067 with open('builtin_functions_ESSL.json' if essl_only else 'builtin_functions.json', 2068 'w') as outfile: 2069 2070 def serialize_obj(obj): 2071 if isinstance(obj, TType): 2072 return obj.data 2073 else: 2074 raise "Cannot serialize to JSON: " + str(obj) 2075 2076 json.dump( 2077 parsed_functions, outfile, indent=4, separators=(',', ': '), default=serialize_obj) 2078 2079 parsed_variables = None 2080 with open(variables_json_filename) as f: 2081 # TODO(http://anglebug.com/3835): skip loading GLSL-only vars when they are added if essl_only 2082 parsed_variables = json.load(f, object_pairs_hook=OrderedDict) 2083 2084 # This script uses a perfect hash function to avoid dealing with collisions 2085 mangled_names = [] 2086 unmangled_names = [] 2087 for group_name, group in parsed_functions.items(): 2088 get_function_names(group, mangled_names, unmangled_names) 2089 for group_name, group in parsed_variables.items(): 2090 get_variable_names(group, mangled_names) 2091 2092 # Hashing mangled names 2093 mangled_names = list(dict.fromkeys(mangled_names)) 2094 num_mangled_names = len(mangled_names) 2095 mangled_names_dict = dict(zip(mangled_names, range(0, len(mangled_names)))) 2096 # Generate the perfect hash function 2097 f1, f2, mangled_G = generate_hash(mangled_names_dict, Hash2) 2098 mangled_hashfn = HashFunction(f1, f2, mangled_G) 2099 mangled_S1 = f1.salt 2100 mangled_S2 = f2.salt 2101 # Array for querying mangled builtins 2102 mangled_builtins = GroupedList(mangled_hashfn, num_mangled_names) 2103 2104 # Hashing unmangled names 2105 unmangled_names = list(dict.fromkeys(unmangled_names)) 2106 num_unmangled_names = len(unmangled_names) 2107 unmangled_names_dict = dict(zip(unmangled_names, range(0, len(unmangled_names)))) 2108 # Generate the perfect hash function 2109 f1, f2, unmangled_G = generate_hash(unmangled_names_dict, Hash2) 2110 unmangled_hashfn = HashFunction(f1, f2, unmangled_G) 2111 unmangled_S1 = f1.salt 2112 unmangled_S2 = f2.salt 2113 # Array for querying unmangled builtins 2114 unmangled_function_if_statements = UnmangledGroupedList(unmangled_hashfn, num_unmangled_names) 2115 2116 for group_name, group in parsed_functions.items(): 2117 process_function_group(group_name, group, symbols, variables, functions, '', 2118 unmangled_function_if_statements, mangled_builtins) 2119 2120 functions.parameter_declarations = prune_parameters_arrays(functions.parameter_declarations, 2121 functions.function_declarations) 2122 2123 for group_name, group in parsed_variables.items(): 2124 process_variable_group('NONE', group_name, group, symbols, variables, mangled_builtins) 2125 2126 mangled_builtins.update_arrays(essl_only) 2127 2128 output_strings = { 2129 'script_name': 2130 os.path.basename(__file__), 2131 'builtin_id_declarations': 2132 '\n'.join(symbols.builtin_id_declarations), 2133 'last_builtin_id': 2134 id_counter - 1, 2135 'name_declarations': 2136 '\n'.join(sorted(list(symbols.name_declarations))), 2137 'function_data_source_name': 2138 functions_txt_filename, 2139 'function_declarations': 2140 '\n'.join(functions.function_declarations), 2141 'parameter_declarations': 2142 '\n'.join(sorted(functions.parameter_declarations)), 2143 'operator_enum_declarations': 2144 '\n'.join(functions.operator_enum_declarations), 2145 'is_in_group_definitions': 2146 '\n'.join(functions.is_in_group_definitions), 2147 'variable_data_source_name': 2148 variables_json_filename, 2149 'type_array_sizes_declarations': 2150 '\n'.join(sorted(variables.type_array_sizes_declarations)), 2151 'variable_declarations': 2152 '\n'.join(sorted(variables.variable_declarations)), 2153 'get_variable_declarations': 2154 '\n'.join(sorted(variables.get_variable_declarations)), 2155 'get_variable_definitions': 2156 '\n'.join(sorted(variables.get_variable_definitions)), 2157 'declare_member_variables': 2158 '\n'.join(variables.declare_member_variables), 2159 'init_member_variables': 2160 '\n'.join(variables.init_member_variables), 2161 'mangled_names_array': 2162 ',\n'.join(mangled_builtins.get_names()), 2163 'mangled_offsets_array': 2164 '\n'.join(mangled_builtins.get_offsets()), 2165 'mangled_rules': 2166 ',\n'.join(mangled_builtins.get_rules()), 2167 'unmangled_array': 2168 ', '.join(unmangled_function_if_statements.get_array()), 2169 'max_unmangled_name_length': 2170 unmangled_function_if_statements.get_max_name_length(), 2171 'max_mangled_name_length': 2172 mangled_builtins.get_max_name_length(), 2173 'num_unmangled_names': 2174 num_unmangled_names, 2175 'num_mangled_names': 2176 num_mangled_names, 2177 'script_generated_hash_tests': 2178 '\n'.join(symbols.script_generated_hash_tests.keys()), 2179 'unmangled_script_generated_hash_tests': 2180 '\n'.join(symbols.unmangled_script_generated_hash_tests.keys()), 2181 'mangled_S1': 2182 str(mangled_S1).replace('[', ' ').replace(']', ' '), 2183 'mangled_S2': 2184 str(mangled_S2).replace('[', ' ').replace(']', ' '), 2185 'mangled_G': 2186 str(mangled_G).replace('[', ' ').replace(']', ' '), 2187 'mangled_NG': 2188 len(mangled_G), 2189 'mangled_NS': 2190 len(mangled_S1), 2191 'unmangled_S1': 2192 str(unmangled_S1).replace('[', ' ').replace(']', ' '), 2193 'unmangled_S2': 2194 str(unmangled_S2).replace('[', ' ').replace(']', ' '), 2195 'unmangled_G': 2196 str(unmangled_G).replace('[', ' ').replace(']', ' '), 2197 'unmangled_NG': 2198 len(unmangled_G), 2199 'unmangled_NS': 2200 len(unmangled_S1), 2201 'header_label': 2202 'ESSL_' if essl_only else 'complete_', 2203 'source_label': 2204 'ESSL_' if essl_only else '' 2205 } 2206 2207 with open(immutablestring_cpp_filename, 'wt') as outfile_cpp: 2208 output_cpp = template_immutablestring_cpp.format(**output_strings) 2209 outfile_cpp.write(output_cpp) 2210 2211 with open(immutablestringtest_cpp_filename, 'wt') as outfile_cpp: 2212 output_cpp = template_immutablestringtest_cpp.format(**output_strings) 2213 outfile_cpp.write(output_cpp) 2214 2215 with open(builtin_header_filename, 'wt') as outfile_header: 2216 output_header = template_builtin_header.format(**output_strings) 2217 outfile_header.write(output_header) 2218 2219 with open(symboltable_cpp_filename, 'wt') as outfile_cpp: 2220 output_cpp = template_symboltable_cpp.format(**output_strings) 2221 outfile_cpp.write(output_cpp) 2222 2223 if not essl_only: 2224 with open(operator_header_filename, 'wt') as outfile_header: 2225 output_header = template_operator_header.format(**output_strings) 2226 outfile_header.write(output_header) 2227 2228 with open(symboltable_header_filename, 'wt') as outfile_h: 2229 output_h = template_symboltable_header.format(**output_strings) 2230 outfile_h.write(output_h) 2231 2232 2233def main(): 2234 random.seed(0) 2235 set_working_dir() 2236 2237 parser = argparse.ArgumentParser() 2238 parser.add_argument( 2239 '--dump-intermediate-json', 2240 help='Dump parsed function data as a JSON file builtin_functions.json', 2241 action="store_true") 2242 parser.add_argument('auto_script_command', nargs='?', default='') 2243 args = parser.parse_args() 2244 2245 test_filename = '../../tests/compiler_tests/ImmutableString_test_autogen.cpp' 2246 essl_test_filename = '../../tests/compiler_tests/ImmutableString_test_ESSL_autogen.cpp' 2247 variables_json_filename = 'builtin_variables.json' 2248 functions_txt_filename = 'builtin_function_declarations.txt' 2249 2250 # auto_script parameters. 2251 if args.auto_script_command != '': 2252 inputs = [ 2253 functions_txt_filename, 2254 variables_json_filename, 2255 ] 2256 outputs = [ 2257 'ImmutableString_autogen.cpp', 2258 'Operator_autogen.h', 2259 'SymbolTable_autogen.cpp', 2260 'SymbolTable_autogen.h', 2261 'tree_util/BuiltIn_complete_autogen.h', 2262 test_filename, 2263 'ImmutableString_ESSL_autogen.cpp', 2264 'SymbolTable_ESSL_autogen.cpp', 2265 'tree_util/BuiltIn_ESSL_autogen.h', 2266 essl_test_filename, 2267 ] 2268 2269 if args.auto_script_command == 'inputs': 2270 print(','.join(inputs)) 2271 elif args.auto_script_command == 'outputs': 2272 print(','.join(outputs)) 2273 else: 2274 print('Invalid script parameters') 2275 return 1 2276 return 0 2277 2278 # Generate files based on GLSL + ESSL symbols 2279 generate_files(False, args, functions_txt_filename, variables_json_filename, 2280 'ImmutableString_autogen.cpp', test_filename, 2281 'tree_util/BuiltIn_complete_autogen.h', 'SymbolTable_autogen.cpp', 2282 'Operator_autogen.h', 'SymbolTable_autogen.h') 2283 2284 # Generate files based on only ESSL symbols 2285 # Symbol table with GLSL + ESSL symbols is too large for Android 2286 generate_files(True, args, functions_txt_filename, variables_json_filename, 2287 'ImmutableString_ESSL_autogen.cpp', essl_test_filename, 2288 'tree_util/BuiltIn_ESSL_autogen.h', 'SymbolTable_ESSL_autogen.cpp', 2289 'Operator_autogen.h', 'SymbolTable_autogen.h') 2290 2291 return 0 2292 2293 2294if __name__ == '__main__': 2295 sys.exit(main()) 2296