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