1 //
2 // Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // TranslatorVulkan:
7 //   A GLSL-based translator that outputs shaders that fit GL_KHR_vulkan_glsl.
8 //   The shaders are then fed into glslang to spit out SPIR-V (libANGLE-side).
9 //   See: https://www.khronos.org/registry/vulkan/specs/misc/GL_KHR_vulkan_glsl.txt
10 //
11 
12 #include "compiler/translator/TranslatorVulkan.h"
13 
14 #include "angle_gl.h"
15 #include "common/utilities.h"
16 #include "compiler/translator/OutputVulkanGLSL.h"
17 #include "compiler/translator/util.h"
18 
19 namespace sh
20 {
21 
22 class DeclareDefaultUniformsTraverser : public TIntermTraverser
23 {
24   public:
DeclareDefaultUniformsTraverser(TInfoSinkBase * sink,ShHashFunction64 hashFunction,NameMap * nameMap)25     DeclareDefaultUniformsTraverser(TInfoSinkBase *sink,
26                                     ShHashFunction64 hashFunction,
27                                     NameMap *nameMap)
28         : TIntermTraverser(true, true, true),
29           mSink(sink),
30           mHashFunction(hashFunction),
31           mNameMap(nameMap),
32           mInDefaultUniform(false)
33     {
34     }
35 
visitDeclaration(Visit visit,TIntermDeclaration * node)36     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
37     {
38         const TIntermSequence &sequence = *(node->getSequence());
39 
40         // TODO(jmadill): Compound declarations.
41         ASSERT(sequence.size() == 1);
42 
43         TIntermTyped *variable = sequence.front()->getAsTyped();
44         const TType &type      = variable->getType();
45         bool isUniform = (type.getQualifier() == EvqUniform) && !IsOpaqueType(type.getBasicType());
46 
47         if (visit == PreVisit)
48         {
49             if (isUniform)
50             {
51                 (*mSink) << "    " << GetTypeName(type, mHashFunction, mNameMap) << " ";
52                 mInDefaultUniform = true;
53             }
54         }
55         else if (visit == InVisit)
56         {
57             mInDefaultUniform = isUniform;
58         }
59         else if (visit == PostVisit)
60         {
61             if (isUniform)
62             {
63                 (*mSink) << ";\n";
64 
65                 // Remove the uniform declaration from the tree so it isn't parsed again.
66                 TIntermSequence emptyReplacement;
67                 mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(
68                     getParentNode()->getAsBlock(), node, emptyReplacement));
69             }
70 
71             mInDefaultUniform = false;
72         }
73         return true;
74     }
75 
visitSymbol(TIntermSymbol * symbol)76     void visitSymbol(TIntermSymbol *symbol) override
77     {
78         if (mInDefaultUniform)
79         {
80             const TName &name = symbol->getName();
81             ASSERT(name.getString().substr(0, 3) != "gl_");
82             (*mSink) << HashName(name, mHashFunction, mNameMap);
83         }
84     }
85 
86   private:
87     TInfoSinkBase *mSink;
88     ShHashFunction64 mHashFunction;
89     NameMap *mNameMap;
90     bool mInDefaultUniform;
91 };
92 
TranslatorVulkan(sh::GLenum type,ShShaderSpec spec)93 TranslatorVulkan::TranslatorVulkan(sh::GLenum type, ShShaderSpec spec)
94     : TCompiler(type, spec, SH_GLSL_450_CORE_OUTPUT)
95 {
96 }
97 
translate(TIntermBlock * root,ShCompileOptions compileOptions,PerformanceDiagnostics *)98 void TranslatorVulkan::translate(TIntermBlock *root,
99                                  ShCompileOptions compileOptions,
100                                  PerformanceDiagnostics * /*perfDiagnostics*/)
101 {
102     TInfoSinkBase &sink = getInfoSink().obj;
103 
104     sink << "#version 450 core\n";
105 
106     // Write out default uniforms into a uniform block assigned to a specific set/binding.
107     int defaultUniformCount = 0;
108     for (const auto &uniform : getUniforms())
109     {
110         if (!uniform.isBuiltIn() && uniform.staticUse && !gl::IsOpaqueType(uniform.type))
111         {
112             ++defaultUniformCount;
113         }
114     }
115 
116     if (defaultUniformCount > 0)
117     {
118         sink << "\nlayout(@@ DEFAULT-UNIFORMS-SET-BINDING @@) uniform defaultUniforms\n{\n";
119 
120         DeclareDefaultUniformsTraverser defaultTraverser(&sink, getHashFunction(), &getNameMap());
121         root->traverse(&defaultTraverser);
122         defaultTraverser.updateTree();
123 
124         sink << "};\n";
125     }
126 
127     // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
128     // if it's core profile shaders and they are used.
129     if (getShaderType() == GL_FRAGMENT_SHADER)
130     {
131         bool hasGLFragColor = false;
132         bool hasGLFragData  = false;
133 
134         for (const auto &outputVar : outputVariables)
135         {
136             if (outputVar.name == "gl_FragColor")
137             {
138                 ASSERT(!hasGLFragColor);
139                 hasGLFragColor = true;
140                 continue;
141             }
142             else if (outputVar.name == "gl_FragData")
143             {
144                 ASSERT(!hasGLFragData);
145                 hasGLFragData = true;
146                 continue;
147             }
148         }
149         ASSERT(!(hasGLFragColor && hasGLFragData));
150         if (hasGLFragColor)
151         {
152             sink << "layout(location = 0) out vec4 webgl_FragColor;\n";
153         }
154         if (hasGLFragData)
155         {
156             sink << "layout(location = 0) out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
157         }
158     }
159 
160     // Write translated shader.
161     TOutputVulkanGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(),
162                                  getNameMap(), &getSymbolTable(), getShaderType(),
163                                  getShaderVersion(), getOutputType(), compileOptions);
164     root->traverse(&outputGLSL);
165 }
166 
shouldFlattenPragmaStdglInvariantAll()167 bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll()
168 {
169     // Not necessary.
170     return false;
171 }
172 
173 }  // namespace sh
174