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