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