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 #ifdef USE_ANGLE_SHADER_PARSER
16 
17 #include "ANGLEShaderParser.h"
18 #include "ShaderTranslator.h"
19 
20 #include "aemu/base/SharedLibrary.h"
21 #include "aemu/base/synchronization/Lock.h"
22 #include "host-common/logging.h"
23 
24 #include <map>
25 #include <string>
26 
27 #include <string.h>
28 
29 #define GL_COMPUTE_SHADER 0x91B9
30 
31 namespace ANGLEShaderParser {
32 
33 ST_BuiltInResources kResources;
34 bool kInitialized = false;
35 bool sIsGles2Gles = false;
36 
37 class LazyLoadedSTDispatch {
38 public:
LazyLoadedSTDispatch()39     LazyLoadedSTDispatch() {
40         memset(&mDispatch, 0, sizeof(STDispatch));
41 
42 #ifdef __APPLE__
43         const char kLibName[] = "libshadertranslator.dylib";
44 #elif defined(_WIN32)
45         const char kLibName[] = "libshadertranslator.dll";
46 #else
47         const char kLibName[] = "libshadertranslator.so";
48 #endif
49         char error[256];
50         mLib = android::base::SharedLibrary::open(kLibName, error, sizeof(error));
51         if (!mLib) {
52             ERR("%s: Could not open shader translator library %s [%s]\n",
53                 __func__, kLibName, error);
54             return;
55         }
56 
57         mDispatch.initialize =
58             (STInitialize_t)mLib->findSymbol("STInitialize");
59         mDispatch.finalize =
60             (STFinalize_t)mLib->findSymbol("STFinalize");
61         mDispatch.generateResources =
62             (STGenerateResources_t)mLib->findSymbol("STGenerateResources");
63         mDispatch.compileAndResolve =
64             (STCompileAndResolve_t)mLib->findSymbol("STCompileAndResolve");
65         mDispatch.freeShaderResolveState =
66             (STFreeShaderResolveState_t)mLib->findSymbol("STFreeShaderResolveState");
67         mDispatch.copyVariable =
68             (STCopyVariable_t)mLib->findSymbol("STCopyVariable");
69         mDispatch.copyInterfaceBlock =
70             (STCopyInterfaceBlock_t)mLib->findSymbol("STCopyInterfaceBlock");
71         mDispatch.destroyVariable =
72             (STDestroyVariable_t)mLib->findSymbol("STDestroyVariable");
73         mDispatch.destroyInterfaceBlock =
74             (STDestroyInterfaceBlock_t)mLib->findSymbol("STDestroyInterfaceBlock");
75 
76         mValid = dispatchValid();
77 
78         if (!mValid) {
79             ERR("%s: error, shader translator dispatch not valid\n", __func__);
80         }
81     }
82 
getDispatch()83     STDispatch* getDispatch() {
84         if (!mValid) return nullptr;
85         return &mDispatch;
86     }
87 
88 private:
dispatchValid()89     bool dispatchValid() {
90         return (nullptr != mDispatch.initialize) &&
91                (nullptr != mDispatch.finalize) &&
92                (nullptr != mDispatch.generateResources) &&
93                (nullptr != mDispatch.compileAndResolve) &&
94                (nullptr != mDispatch.copyVariable) &&
95                (nullptr != mDispatch.copyInterfaceBlock) &&
96                (nullptr != mDispatch.destroyVariable) &&
97                (nullptr != mDispatch.destroyInterfaceBlock);
98     }
99 
100     android::base::SharedLibrary* mLib = nullptr;
101     bool mValid = false;
102     STDispatch mDispatch;
103 };
104 
105 
getSTDispatch()106 static STDispatch* getSTDispatch() {
107     static LazyLoadedSTDispatch* dispatch = new LazyLoadedSTDispatch;
108     return dispatch->getDispatch();
109 }
110 
111 ShaderLinkInfo::ShaderLinkInfo() = default;
ShaderLinkInfo(const ShaderLinkInfo & other)112 ShaderLinkInfo::ShaderLinkInfo(const ShaderLinkInfo& other) {
113     clear();
114     copyFromOther(other);
115 }
116 
operator =(const ShaderLinkInfo & other)117 ShaderLinkInfo& ShaderLinkInfo::operator=(const ShaderLinkInfo& other) {
118     if (this != &other) {
119         ShaderLinkInfo tmp(other);
120         *this = std::move(tmp);
121     }
122     return *this;
123 }
124 
ShaderLinkInfo(ShaderLinkInfo && other)125 ShaderLinkInfo::ShaderLinkInfo(ShaderLinkInfo&& other) {
126     *this = std::move(other);
127 }
128 
operator =(ShaderLinkInfo && other)129 ShaderLinkInfo& ShaderLinkInfo::operator=(ShaderLinkInfo&& other) {
130     esslVersion = other.esslVersion;
131     uniforms = std::move(other.uniforms);
132     varyings = std::move(other.varyings);
133     attributes = std::move(other.attributes);
134     outputVars = std::move(other.outputVars);
135     nameMap = std::move(other.nameMap);
136     nameMapReverse = std::move(other.nameMapReverse);
137 
138     return *this;
139 }
140 
~ShaderLinkInfo()141 ShaderLinkInfo::~ShaderLinkInfo() {
142     clear();
143 }
144 
copyFromOther(const ShaderLinkInfo & other)145 void ShaderLinkInfo::copyFromOther(const ShaderLinkInfo& other) {
146     esslVersion = other.esslVersion;
147 
148     if (!sIsGles2Gles) {
149         auto dispatch = getSTDispatch();
150         for (const auto& var: other.uniforms) { uniforms.push_back(dispatch->copyVariable(&var)); }
151         for (const auto& var: other.varyings) { varyings.push_back(dispatch->copyVariable(&var)); }
152         for (const auto& var: other.attributes) { attributes.push_back(dispatch->copyVariable(&var)); }
153         for (const auto& var: other.outputVars) { outputVars.push_back(dispatch->copyVariable(&var)); }
154         for (const auto& var: other.interfaceBlocks) { interfaceBlocks.push_back(dispatch->copyInterfaceBlock(&var)); }
155     }
156 
157     nameMap = other.nameMap;
158     nameMapReverse = other.nameMapReverse;
159 }
160 
clear()161 void ShaderLinkInfo::clear() {
162 
163     if (!sIsGles2Gles) {
164         auto dispatch = getSTDispatch();
165         for (auto& var: uniforms) { dispatch->destroyVariable(&var); }
166         for (auto& var: varyings) { dispatch->destroyVariable(&var); }
167         for (auto& var: attributes) { dispatch->destroyVariable(&var); }
168         for (auto& var: outputVars) { dispatch->destroyVariable(&var); }
169         for (auto& var: interfaceBlocks) { dispatch->destroyInterfaceBlock(&var); }
170     }
171 
172     uniforms.clear();
173     varyings.clear();
174     attributes.clear();
175     outputVars.clear();
176     interfaceBlocks.clear();
177     nameMap.clear();
178     nameMapReverse.clear();
179 }
180 
181 struct ShaderSpecKey {
182     GLenum shaderType;
183     int esslVersion;
184 };
185 
sInputSpecForVersion(int esslVersion)186 static ST_ShaderSpec sInputSpecForVersion(int esslVersion) {
187     switch (esslVersion) {
188         case 100:
189             return ST_GLES2_SPEC;
190         case 300:
191             return ST_GLES3_SPEC;
192         case 310:
193             return ST_GLES3_1_SPEC;
194     }
195     return ST_GLES3_1_SPEC;
196 }
197 
sOutputSpecForVersion(bool coreProfileHost,int esslVersion)198 static ST_ShaderOutput sOutputSpecForVersion(bool coreProfileHost, int esslVersion) {
199     switch (esslVersion) {
200         case 100:
201             if (coreProfileHost) {
202                 return ST_GLSL_330_CORE_OUTPUT;
203             } else {
204                 return ST_GLSL_COMPATIBILITY_OUTPUT;
205             }
206         case 300:
207             if (coreProfileHost) {
208                 return ST_GLSL_330_CORE_OUTPUT;
209             } else {
210                 return ST_GLSL_150_CORE_OUTPUT;
211             }
212         case 310:
213             return ST_GLSL_430_CORE_OUTPUT;
214     }
215     return ST_GLSL_430_CORE_OUTPUT;
216 }
217 
218 struct ShaderSpecKeyCompare {
operator ()ANGLEShaderParser::ShaderSpecKeyCompare219     bool operator() (const ShaderSpecKey& a,
220                      const ShaderSpecKey& b) const {
221         if (a.shaderType != b.shaderType)
222             return a.shaderType < b.shaderType;
223         if (a.esslVersion != b.esslVersion)
224             return a.esslVersion < b.esslVersion;
225         return false;
226     }
227 };
228 
229 typedef std::map<ShaderSpecKey, ST_Handle, ShaderSpecKeyCompare> ShaderCompilerMap;
sCompilerMap()230 static ShaderCompilerMap* sCompilerMap() {
231     static ShaderCompilerMap* m = new ShaderCompilerMap;
232     return m;
233 }
234 
getShaderCompiler(bool coreProfileHost,ShaderSpecKey key)235 static ST_Handle getShaderCompiler(bool coreProfileHost, ShaderSpecKey key) {
236     auto it = sCompilerMap()->find(key);
237     if (it == sCompilerMap()->end()) return (ST_Handle)nullptr;
238     return it->second;
239 }
240 
241 android::base::Lock kCompilerLock;
242 
initializeResources(BuiltinResourcesEditCallback callback)243 void initializeResources(
244     BuiltinResourcesEditCallback callback) {
245 
246     if (!sIsGles2Gles) {
247         getSTDispatch()->generateResources(&kResources);
248     }
249 
250     callback(kResources);
251 }
252 
globalInitialize(bool isGles2Gles,BuiltinResourcesEditCallback editCallback)253 bool globalInitialize(
254     bool isGles2Gles,
255     BuiltinResourcesEditCallback editCallback) {
256 
257     sIsGles2Gles = isGles2Gles;
258 
259     if (!sIsGles2Gles) {
260         getSTDispatch()->initialize();
261     }
262 
263     initializeResources(editCallback);
264 
265     kInitialized = true;
266     return true;
267 }
268 
269 template <class T>
convertArrayToVecWithCopy(unsigned int count,const T * pItems,T (* copyFunc)(const T *))270 static std::vector<T> convertArrayToVecWithCopy(
271     unsigned int count, const T* pItems, T (*copyFunc)(const T*)) {
272     std::vector<T> res;
273     for (uint32_t i = 0; i < count; ++i) {
274         res.push_back(copyFunc(pItems + i));
275     }
276     return res;
277 }
278 
getShaderLinkInfo(int esslVersion,const ST_ShaderCompileResult * compileResult,ShaderLinkInfo * linkInfo)279 static void getShaderLinkInfo(int esslVersion,
280                               const ST_ShaderCompileResult* compileResult,
281                               ShaderLinkInfo* linkInfo) {
282     linkInfo->esslVersion = esslVersion;
283     linkInfo->uniforms.clear();
284     linkInfo->varyings.clear();
285     linkInfo->attributes.clear();
286     linkInfo->outputVars.clear();
287     linkInfo->interfaceBlocks.clear();
288 
289     for (uint32_t i = 0; i < compileResult->nameHashingMap->entryCount; ++i) {
290         linkInfo->nameMap[compileResult->nameHashingMap->ppUserNames[i]] =
291             compileResult->nameHashingMap->ppCompiledNames[i];
292     }
293 
294     for (const auto& elt : linkInfo->nameMap) {
295         linkInfo->nameMapReverse[elt.second] = elt.first;
296     }
297 
298     auto st = getSTDispatch();
299     auto stCopyVariable = st->copyVariable;
300     auto stCopyInterfaceBlock = st->copyInterfaceBlock;
301 
302     linkInfo->uniforms = convertArrayToVecWithCopy(
303         compileResult->uniformsCount,
304         compileResult->pUniforms,
305         stCopyVariable);
306 
307     std::vector<ST_ShaderVariable> inputVaryings =
308         convertArrayToVecWithCopy(
309             compileResult->inputVaryingsCount, compileResult->pInputVaryings,
310             stCopyVariable);
311     std::vector<ST_ShaderVariable> outputVaryings =
312         convertArrayToVecWithCopy(
313             compileResult->outputVaryingsCount, compileResult->pOutputVaryings,
314             stCopyVariable);
315 
316     linkInfo->varyings.clear();
317     linkInfo->varyings.insert(
318         linkInfo->varyings.begin(),
319         inputVaryings.begin(),
320         inputVaryings.end());
321     linkInfo->varyings.insert(
322         linkInfo->varyings.begin(),
323         outputVaryings.begin(),
324         outputVaryings.end());
325 
326     linkInfo->attributes =
327         convertArrayToVecWithCopy(
328             compileResult->allAttributesCount,
329             compileResult->pAllAttributes,
330             stCopyVariable);
331 
332     linkInfo->outputVars =
333         convertArrayToVecWithCopy(
334             compileResult->activeOutputVariablesCount,
335             compileResult->pActiveOutputVariables,
336             stCopyVariable);
337 
338     linkInfo->interfaceBlocks =
339         convertArrayToVecWithCopy(
340             compileResult->uniformBlocksCount,
341             compileResult->pUniformBlocks,
342             stCopyInterfaceBlock);
343     // todo: split to uniform and ssbo
344 }
345 
detectShaderESSLVersion(const char * const * strings)346 static int detectShaderESSLVersion(const char* const* strings) {
347     // Just look at the first line of the first string for now
348     const char* pos = strings[0];
349     const char* linePos = strstr(pos, "\n");
350     const char* versionPos = strstr(pos, "#version");
351     if (!linePos || !versionPos) {
352         // default to ESSL 100
353         return 100;
354     }
355 
356     const char* version_end = versionPos + strlen("#version");
357     int wantedESSLVersion;
358     sscanf(version_end, " %d", &wantedESSLVersion);
359     return wantedESSLVersion;
360 }
361 
translate(bool hostUsesCoreProfile,const char * src,GLenum shaderType,std::string * outInfolog,std::string * outObjCode,ShaderLinkInfo * outShaderLinkInfo)362 bool translate(bool hostUsesCoreProfile,
363                const char* src,
364                GLenum shaderType,
365                std::string* outInfolog,
366                std::string* outObjCode,
367                ShaderLinkInfo* outShaderLinkInfo) {
368     int esslVersion = detectShaderESSLVersion(&src);
369 
370     // Leverage ARB_ES3_1_compatibility for ESSL 310 for now.
371     // Use translator after rest of dEQP-GLES31.functional is in a better state.
372     if (esslVersion == 310) {
373         // Don't try to get obj code just yet.
374         // At least on NVIDIA Quadro K2200 Linux (361.xx),
375         // ARB_ES3_1_compatibility seems to assume incorrectly
376         // that atomic_uint must catch a precision qualifier in ESSL 310.
377         std::string origSrc(src);
378         outShaderLinkInfo->esslVersion = esslVersion;
379         size_t versionStart = origSrc.find("#version");
380         size_t versionEnd = origSrc.find("\n", versionStart);
381         size_t extensionStart = origSrc.rfind("#extension");
382         size_t extensionEnd = origSrc.find("\n", extensionStart);
383         if (extensionStart == std::string::npos) {
384             std::string versionPart = origSrc.substr(versionStart, versionEnd - versionStart + 1);
385             std::string src2 =
386                 versionPart + "precision highp atomic_uint;\n" +
387                 origSrc.substr(versionEnd + 1, origSrc.size() - (versionEnd + 1));
388             *outObjCode = src2;
389         } else {
390             std::string uptoExtensionPart = origSrc.substr(0, extensionEnd + 1);
391             std::string src2 =
392                 uptoExtensionPart + "precision highp atomic_uint;\n" +
393                 origSrc.substr(extensionEnd + 1, origSrc.size() - (extensionEnd + 1));
394             *outObjCode = src2;
395         }
396         return true;
397     }
398 
399 	if (!kInitialized) {
400         return false;
401     }
402 
403     // ANGLE may crash if multiple RenderThreads attempt to compile shaders
404     // at the same time.
405     android::base::AutoLock autolock(kCompilerLock);
406 
407     ShaderSpecKey key;
408     key.shaderType = shaderType;
409     key.esslVersion = esslVersion;
410 
411     ST_ShaderCompileInfo ci = {
412         (ST_Handle)getShaderCompiler(hostUsesCoreProfile, key),
413         shaderType,
414         sInputSpecForVersion(esslVersion),
415         sOutputSpecForVersion(hostUsesCoreProfile, esslVersion),
416         ST_OBJECT_CODE | ST_VARIABLES,
417         &kResources,
418         src,
419     };
420 
421     ST_ShaderCompileResult* res = nullptr;
422 
423     auto st = getSTDispatch();
424     st->compileAndResolve(&ci, &res);
425 
426     sCompilerMap()->emplace(key, res->outputHandle);
427     *outInfolog = std::string(res->infoLog);
428     *outObjCode = std::string(res->translatedSource);
429 
430     if (outShaderLinkInfo) getShaderLinkInfo(esslVersion, res, outShaderLinkInfo);
431 
432     bool ret = res->compileStatus == 1;
433 
434     st->freeShaderResolveState(res);
435     return ret;
436 }
437 
438 } // namespace ANGLEShaderParser
439 
440 #endif
441