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