• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "ANGLEShaderParser.h"
16 #include "ShaderTranslator.h"
17 
18 #include "base/Lock.h"
19 
20 #include <map>
21 #include <string>
22 
23 #include <string.h>
24 
25 #define GL_COMPUTE_SHADER 0x91B9
26 
27 namespace ANGLEShaderParser {
28 
29 ST_BuiltInResources kResources;
30 bool kInitialized = false;
31 bool sIsGles2Gles = false;
32 
33 ShaderLinkInfo::ShaderLinkInfo() = default;
ShaderLinkInfo(const ShaderLinkInfo & other)34 ShaderLinkInfo::ShaderLinkInfo(const ShaderLinkInfo& other) {
35     clear();
36     copyFromOther(other);
37 }
38 
operator =(const ShaderLinkInfo & other)39 ShaderLinkInfo& ShaderLinkInfo::operator=(const ShaderLinkInfo& other) {
40     if (this != &other) {
41         ShaderLinkInfo tmp(other);
42         *this = std::move(tmp);
43     }
44     return *this;
45 }
46 
ShaderLinkInfo(ShaderLinkInfo && other)47 ShaderLinkInfo::ShaderLinkInfo(ShaderLinkInfo&& other) {
48     *this = std::move(other);
49 }
50 
operator =(ShaderLinkInfo && other)51 ShaderLinkInfo& ShaderLinkInfo::operator=(ShaderLinkInfo&& other) {
52     esslVersion = other.esslVersion;
53     uniforms = std::move(other.uniforms);
54     varyings = std::move(other.varyings);
55     attributes = std::move(other.attributes);
56     outputVars = std::move(other.outputVars);
57     nameMap = std::move(other.nameMap);
58     nameMapReverse = std::move(other.nameMapReverse);
59 
60     return *this;
61 }
62 
~ShaderLinkInfo()63 ShaderLinkInfo::~ShaderLinkInfo() {
64     clear();
65 }
66 
copyFromOther(const ShaderLinkInfo & other)67 void ShaderLinkInfo::copyFromOther(const ShaderLinkInfo& other) {
68     esslVersion = other.esslVersion;
69 
70     if (!sIsGles2Gles) {
71         for (const auto& var: other.uniforms) { uniforms.push_back(STCopyVariable(&var)); }
72         for (const auto& var: other.varyings) { varyings.push_back(STCopyVariable(&var)); }
73         for (const auto& var: other.attributes) { attributes.push_back(STCopyVariable(&var)); }
74         for (const auto& var: other.outputVars) { outputVars.push_back(STCopyVariable(&var)); }
75         for (const auto& var: other.interfaceBlocks) { interfaceBlocks.push_back(STCopyInterfaceBlock(&var)); }
76     }
77 
78     nameMap = other.nameMap;
79     nameMapReverse = other.nameMapReverse;
80 }
81 
clear()82 void ShaderLinkInfo::clear() {
83 
84     if (!sIsGles2Gles) {
85         for (auto& var: uniforms) { STDestroyVariable(&var); }
86         for (auto& var: varyings) { STDestroyVariable(&var); }
87         for (auto& var: attributes) { STDestroyVariable(&var); }
88         for (auto& var: outputVars) { STDestroyVariable(&var); }
89         for (auto& var: interfaceBlocks) { STDestroyInterfaceBlock(&var); }
90     }
91 
92     uniforms.clear();
93     varyings.clear();
94     attributes.clear();
95     outputVars.clear();
96     interfaceBlocks.clear();
97     nameMap.clear();
98     nameMapReverse.clear();
99 }
100 
101 struct ShaderSpecKey {
102     GLenum shaderType;
103     int esslVersion;
104 };
105 
sInputSpecForVersion(int esslVersion)106 static ST_ShaderSpec sInputSpecForVersion(int esslVersion) {
107     switch (esslVersion) {
108         case 100:
109             return ST_GLES2_SPEC;
110         case 300:
111             return ST_GLES3_SPEC;
112         case 310:
113             return ST_GLES3_1_SPEC;
114     }
115     return ST_GLES3_1_SPEC;
116 }
117 
sOutputSpecForVersion(bool coreProfileHost,int esslVersion)118 static ST_ShaderOutput sOutputSpecForVersion(bool coreProfileHost, int esslVersion) {
119     switch (esslVersion) {
120         case 100:
121             if (coreProfileHost) {
122                 return ST_GLSL_330_CORE_OUTPUT;
123             } else {
124                 return ST_GLSL_COMPATIBILITY_OUTPUT;
125             }
126         case 300:
127             if (coreProfileHost) {
128                 return ST_GLSL_330_CORE_OUTPUT;
129             } else {
130                 return ST_GLSL_150_CORE_OUTPUT;
131             }
132         case 310:
133             return ST_GLSL_430_CORE_OUTPUT;
134     }
135     return ST_GLSL_430_CORE_OUTPUT;
136 }
137 
138 struct ShaderSpecKeyCompare {
operator ()ANGLEShaderParser::ShaderSpecKeyCompare139     bool operator() (const ShaderSpecKey& a,
140                      const ShaderSpecKey& b) const {
141         if (a.shaderType != b.shaderType)
142             return a.shaderType < b.shaderType;
143         if (a.esslVersion != b.esslVersion)
144             return a.esslVersion < b.esslVersion;
145         return false;
146     }
147 };
148 
149 typedef std::map<ShaderSpecKey, ST_Handle, ShaderSpecKeyCompare> ShaderCompilerMap;
sCompilerMap()150 static ShaderCompilerMap* sCompilerMap() {
151     static ShaderCompilerMap* m = new ShaderCompilerMap;
152     return m;
153 }
154 
getShaderCompiler(bool coreProfileHost,ShaderSpecKey key)155 static ST_Handle getShaderCompiler(bool coreProfileHost, ShaderSpecKey key) {
156     auto it = sCompilerMap()->find(key);
157     if (it == sCompilerMap()->end()) return (ST_Handle)nullptr;
158     return it->second;
159 }
160 
161 android::base::Lock kCompilerLock;
162 
initializeResources(BuiltinResourcesEditCallback callback)163 void initializeResources(
164     BuiltinResourcesEditCallback callback) {
165 
166     if (!sIsGles2Gles) {
167         STGenerateResources(&kResources);
168     }
169 
170     callback(kResources);
171 }
172 
globalInitialize(bool isGles2Gles,BuiltinResourcesEditCallback editCallback)173 bool globalInitialize(
174     bool isGles2Gles,
175     BuiltinResourcesEditCallback editCallback) {
176 
177     sIsGles2Gles = isGles2Gles;
178 
179     if (!sIsGles2Gles) {
180         STInitialize();
181     }
182 
183     initializeResources(editCallback);
184 
185     kInitialized = true;
186     return true;
187 }
188 
189 template <class T>
convertArrayToVecWithCopy(unsigned int count,const T * pItems,T (* copyFunc)(const T *))190 static std::vector<T> convertArrayToVecWithCopy(
191     unsigned int count, const T* pItems, T (*copyFunc)(const T*)) {
192     std::vector<T> res;
193     for (uint32_t i = 0; i < count; ++i) {
194         res.push_back(copyFunc(pItems + i));
195     }
196     return res;
197 }
198 
getShaderLinkInfo(int esslVersion,const ST_ShaderCompileResult * compileResult,ShaderLinkInfo * linkInfo)199 static void getShaderLinkInfo(int esslVersion,
200                               const ST_ShaderCompileResult* compileResult,
201                               ShaderLinkInfo* linkInfo) {
202     linkInfo->esslVersion = esslVersion;
203     linkInfo->uniforms.clear();
204     linkInfo->varyings.clear();
205     linkInfo->attributes.clear();
206     linkInfo->outputVars.clear();
207     linkInfo->interfaceBlocks.clear();
208 
209     for (uint32_t i = 0; i < compileResult->nameHashingMap->entryCount; ++i) {
210         linkInfo->nameMap[compileResult->nameHashingMap->ppUserNames[i]] =
211             compileResult->nameHashingMap->ppCompiledNames[i];
212     }
213 
214     for (const auto& elt : linkInfo->nameMap) {
215         linkInfo->nameMapReverse[elt.second] = elt.first;
216     }
217 
218     linkInfo->uniforms = convertArrayToVecWithCopy(
219         compileResult->uniformsCount,
220         compileResult->pUniforms,
221         STCopyVariable);
222 
223     std::vector<ST_ShaderVariable> inputVaryings =
224         convertArrayToVecWithCopy(
225             compileResult->inputVaryingsCount, compileResult->pInputVaryings,
226             STCopyVariable);
227     std::vector<ST_ShaderVariable> outputVaryings =
228         convertArrayToVecWithCopy(
229             compileResult->outputVaryingsCount, compileResult->pOutputVaryings,
230             STCopyVariable);
231 
232     linkInfo->varyings.clear();
233     linkInfo->varyings.insert(
234         linkInfo->varyings.begin(),
235         inputVaryings.begin(),
236         inputVaryings.end());
237     linkInfo->varyings.insert(
238         linkInfo->varyings.begin(),
239         outputVaryings.begin(),
240         outputVaryings.end());
241 
242     linkInfo->attributes =
243         convertArrayToVecWithCopy(
244             compileResult->allAttributesCount,
245             compileResult->pAllAttributes,
246             STCopyVariable);
247 
248     linkInfo->outputVars =
249         convertArrayToVecWithCopy(
250             compileResult->activeOutputVariablesCount,
251             compileResult->pActiveOutputVariables,
252             STCopyVariable);
253 
254     linkInfo->interfaceBlocks =
255         convertArrayToVecWithCopy(
256             compileResult->uniformBlocksCount,
257             compileResult->pUniformBlocks,
258             STCopyInterfaceBlock);
259     // todo: split to uniform and ssbo
260 }
261 
detectShaderESSLVersion(const char * const * strings)262 static int detectShaderESSLVersion(const char* const* strings) {
263     // Just look at the first line of the first string for now
264     const char* pos = strings[0];
265     const char* linePos = strstr(pos, "\n");
266     const char* versionPos = strstr(pos, "#version");
267     if (!linePos || !versionPos) {
268         // default to ESSL 100
269         return 100;
270     }
271 
272     const char* version_end = versionPos + strlen("#version");
273     int wantedESSLVersion;
274     sscanf(version_end, " %d", &wantedESSLVersion);
275     return wantedESSLVersion;
276 }
277 
translate(bool hostUsesCoreProfile,const char * src,GLenum shaderType,std::string * outInfolog,std::string * outObjCode,ShaderLinkInfo * outShaderLinkInfo)278 bool translate(bool hostUsesCoreProfile,
279                const char* src,
280                GLenum shaderType,
281                std::string* outInfolog,
282                std::string* outObjCode,
283                ShaderLinkInfo* outShaderLinkInfo) {
284     int esslVersion = detectShaderESSLVersion(&src);
285 
286     // Leverage ARB_ES3_1_compatibility for ESSL 310 for now.
287     // Use translator after rest of dEQP-GLES31.functional is in a better state.
288     if (esslVersion == 310) {
289         // Don't try to get obj code just yet.
290         // At least on NVIDIA Quadro K2200 Linux (361.xx),
291         // ARB_ES3_1_compatibility seems to assume incorrectly
292         // that atomic_uint must catch a precision qualifier in ESSL 310.
293         std::string origSrc(src);
294         outShaderLinkInfo->esslVersion = esslVersion;
295         size_t versionStart = origSrc.find("#version");
296         size_t versionEnd = origSrc.find("\n", versionStart);
297         size_t extensionStart = origSrc.rfind("#extension");
298         size_t extensionEnd = origSrc.find("\n", extensionStart);
299         if (extensionStart == std::string::npos) {
300             std::string versionPart = origSrc.substr(versionStart, versionEnd - versionStart + 1);
301             std::string src2 =
302                 versionPart + "precision highp atomic_uint;\n" +
303                 origSrc.substr(versionEnd + 1, origSrc.size() - (versionEnd + 1));
304             *outObjCode = src2;
305         } else {
306             std::string uptoExtensionPart = origSrc.substr(0, extensionEnd + 1);
307             std::string src2 =
308                 uptoExtensionPart + "precision highp atomic_uint;\n" +
309                 origSrc.substr(extensionEnd + 1, origSrc.size() - (extensionEnd + 1));
310             *outObjCode = src2;
311         }
312         return true;
313     }
314 
315 	if (!kInitialized) {
316         return false;
317     }
318 
319     // ANGLE may crash if multiple RenderThreads attempt to compile shaders
320     // at the same time.
321     android::base::AutoLock autolock(kCompilerLock);
322 
323     ShaderSpecKey key;
324     key.shaderType = shaderType;
325     key.esslVersion = esslVersion;
326 
327     ST_ShaderCompileInfo ci = {
328         (ST_Handle)getShaderCompiler(hostUsesCoreProfile, key),
329         shaderType,
330         sInputSpecForVersion(esslVersion),
331         sOutputSpecForVersion(hostUsesCoreProfile, esslVersion),
332         ST_OBJECT_CODE | ST_VARIABLES,
333         &kResources,
334         src,
335     };
336 
337     ST_ShaderCompileResult* res = nullptr;
338 
339     STCompileAndResolve(&ci, &res);
340 
341     sCompilerMap()->emplace(key, res->outputHandle);
342     *outInfolog = std::string(res->infoLog);
343     *outObjCode = std::string(res->translatedSource);
344 
345     if (outShaderLinkInfo) getShaderLinkInfo(esslVersion, res, outShaderLinkInfo);
346 
347     bool ret = res->compileStatus == 1;
348 
349     STFreeShaderResolveState(res);
350     return ret;
351 }
352 
353 } // namespace ANGLEShaderParser
354