1 #include "GLSLANG/ShaderLang.h"
2
3 #include "angle_gl.h"
4 #include "ShaderTranslator.h"
5
6 #include <assert.h>
7 #include <math.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sstream>
12 #include <vector>
13 #include <map>
14 #include <string>
15
16 namespace {
17
boolToUint(bool b)18 unsigned int boolToUint(bool b) {
19 return b ? 1 : 0;
20 }
21
22 template<class S, class T>
toAllocedCArray(const S & xs)23 static T* toAllocedCArray(const S& xs) {
24 size_t bytes = sizeof(T) * xs.size();
25 T* res = (T *)malloc(bytes);
26 memset(res, 0, bytes);
27 memcpy(res, xs.data(), bytes);
28 return res;
29 }
30
toAllocedCString(const std::string & str)31 static const char* toAllocedCString(const std::string& str) {
32 size_t bytes = sizeof(char) * str.size() + 1;
33 char* res = (char *)malloc(bytes);
34 memset(res, 0, bytes);
35 memcpy(res, str.data(), bytes);
36 return res;
37 }
38
39 template <class T>
dupCArray(unsigned int count,const T * pItems)40 T* dupCArray(unsigned int count, const T* pItems) {
41 if (0 == count) return nullptr;
42
43 size_t bytes = count * sizeof(T);
44 T* res = (T*)malloc(count * bytes);
45 memcpy(res, pItems, bytes);
46 return res;
47 }
48
49 static void fillShaderVariable(const sh::ShaderVariable& var, ST_ShaderVariable* out);
50 static void fillInterfaceBlock(const sh::InterfaceBlock& ib, ST_InterfaceBlock* out);
51
52 static ST_NameHashingMap* createNameHashingMap(const std::map<std::string, std::string>& inputMap);
53 static ST_ShaderVariable* createShaderVariableArray(const std::vector<sh::ShaderVariable>& inputVars);
54 static ST_InterfaceBlock* createInterfaceBlockArray(const std::vector<sh::InterfaceBlock>& inputBlocks);
55
56 static void initShaderVariableInfo(
57 const std::vector<sh::ShaderVariable>* pInputs,
58 unsigned int* pCount,
59 ST_ShaderVariable** pOutputs);
60
61 static void initInterfaceBlockInfo(
62 const std::vector<sh::InterfaceBlock>* pInputs,
63 unsigned int* pCount,
64 ST_InterfaceBlock** pOutputs);
65
66 static std::vector<sh::ShaderVariable> getActiveVariables(
67 const std::vector<sh::ShaderVariable>* pInputs);
68
69 static void freeNameHashingMap(ST_NameHashingMap* nameHashingMap);
70 static void destroyShaderVariable(ST_ShaderVariable* var);
71 static void freeShaderVariableArray(uint32_t count, ST_ShaderVariable* vars);
72 static void destroyInterfaceBlock(ST_InterfaceBlock* ib);
73 static void freeInterfaceBlockArray(uint32_t count, ST_InterfaceBlock* ibs);
74
fillShaderVariable(const sh::ShaderVariable & var,ST_ShaderVariable * out)75 static void fillShaderVariable(const sh::ShaderVariable& var, ST_ShaderVariable* out) {
76 out->type = var.type;
77 out->precision = var.precision;
78
79 out->name = toAllocedCString(var.name);
80 out->mappedName = toAllocedCString(var.mappedName);
81
82 out->arraySizeCount = (uint32_t)var.arraySizes.size();
83 out->pArraySizes = toAllocedCArray<std::vector<unsigned int>, unsigned int>(var.arraySizes);
84
85 out->staticUse = boolToUint(var.staticUse);
86 out->active = boolToUint(var.active);
87
88 out->fieldsCount = (uint32_t)var.fields.size();
89 out->pFields = toAllocedCArray<std::vector<sh::ShaderVariable>, ST_ShaderVariable>(var.fields);
90 for (uint32_t i = 0; i < out->fieldsCount; ++i) {
91 fillShaderVariable(var.fields[i], out->pFields + i);
92 }
93
94 out->structName = toAllocedCString(var.structName);
95
96 out->isRowMajorLayout = boolToUint(var.isRowMajorLayout);
97
98 out->location = var.location;
99
100 out->binding = var.binding;
101
102 out->imageUnitFormat = var.imageUnitFormat;
103 out->offset = var.offset;
104 out->readonly = boolToUint(var.readonly);
105 out->writeonly = boolToUint(var.writeonly);
106
107 out->index = var.index;
108
109 out->interpolation = (ST_InterpolationType)(var.interpolation);
110 out->isInvariant = boolToUint(var.isInvariant);
111
112 out->flattenedOffsetInParentArrays = var.parentArrayIndex();
113 }
114
fillInterfaceBlock(const sh::InterfaceBlock & ib,ST_InterfaceBlock * out)115 static void fillInterfaceBlock(const sh::InterfaceBlock& ib, ST_InterfaceBlock* out) {
116 out->name = toAllocedCString(ib.name);
117 out->mappedName = toAllocedCString(ib.mappedName);
118 out->instanceName = toAllocedCString(ib.mappedName);
119
120 out->arraySize = ib.arraySize;
121 out->layout = (ST_BlockLayoutType)ib.layout;
122
123 out->isRowMajorLayout = boolToUint(ib.isRowMajorLayout);
124
125 out->binding = ib.binding;
126 out->staticUse = boolToUint(ib.staticUse);
127 out->active = boolToUint(ib.active);
128 out->blockType = (ST_BlockType)ib.blockType;
129
130 out->fieldsCount = (uint32_t)ib.fields.size();
131 out->pFields = toAllocedCArray<std::vector<sh::ShaderVariable>, ST_ShaderVariable>(ib.fields);
132 for (uint32_t i = 0; i < out->fieldsCount; ++i) {
133 fillShaderVariable(ib.fields[i], out->pFields + i);
134 }
135 }
136
createNameHashingMap(const std::map<std::string,std::string> & inputMap)137 static ST_NameHashingMap* createNameHashingMap(const std::map<std::string, std::string>& inputMap) {
138 size_t elements = inputMap.size();
139
140 const char** ppUserNames = (const char**)malloc(elements * sizeof(const char*));
141 const char** ppCompiledNames = (const char**)malloc(elements * sizeof(const char* const*));
142 size_t i = 0;
143
144 for (auto it : inputMap) {
145 ppUserNames[i] = toAllocedCString(it.first);
146 ppCompiledNames[i] = toAllocedCString(it.second);
147 ++i;
148 }
149
150 ST_NameHashingMap* res = (ST_NameHashingMap*)(malloc(sizeof(ST_NameHashingMap)));
151
152 res->entryCount = (uint32_t)elements;
153 res->ppUserNames = ppUserNames;
154 res->ppCompiledNames = ppCompiledNames;
155
156 return res;
157 }
158
159
createShaderVariableArray(const std::vector<sh::ShaderVariable> & inputVars)160 static ST_ShaderVariable* createShaderVariableArray(const std::vector<sh::ShaderVariable>& inputVars) {
161 ST_ShaderVariable* res =
162 toAllocedCArray<std::vector<sh::ShaderVariable>, ST_ShaderVariable>(inputVars);
163 for (size_t i = 0; i < inputVars.size(); ++i) {
164 fillShaderVariable(inputVars[i], res + i);
165 }
166 return res;
167 }
168
createInterfaceBlockArray(const std::vector<sh::InterfaceBlock> & inputBlocks)169 static ST_InterfaceBlock* createInterfaceBlockArray(const std::vector<sh::InterfaceBlock>& inputBlocks) {
170 ST_InterfaceBlock* res =
171 toAllocedCArray<std::vector<sh::InterfaceBlock>, ST_InterfaceBlock>(inputBlocks);
172 for (size_t i = 0; i < inputBlocks.size(); ++i) {
173 fillInterfaceBlock(inputBlocks[i], res + i);
174 }
175 return res;
176 }
177
initShaderVariableInfo(const std::vector<sh::ShaderVariable> * pInputs,unsigned int * pCount,ST_ShaderVariable ** pOutputs)178 static void initShaderVariableInfo(
179 const std::vector<sh::ShaderVariable>* pInputs,
180 unsigned int* pCount,
181 ST_ShaderVariable** pOutputs) {
182 *pCount = pInputs->size();
183 *pOutputs = createShaderVariableArray(*pInputs);
184 }
185
initInterfaceBlockInfo(const std::vector<sh::InterfaceBlock> * pInputs,unsigned int * pCount,ST_InterfaceBlock ** pOutputs)186 static void initInterfaceBlockInfo(
187 const std::vector<sh::InterfaceBlock>* pInputs,
188 unsigned int* pCount,
189 ST_InterfaceBlock** pOutputs) {
190 *pCount = pInputs->size();
191 *pOutputs = createInterfaceBlockArray(*pInputs);
192 }
193
getActiveVariables(const std::vector<sh::ShaderVariable> * pInputs)194 static std::vector<sh::ShaderVariable> getActiveVariables(
195 const std::vector<sh::ShaderVariable>* pInputs) {
196 std::vector<sh::ShaderVariable> activeVars;
197 for (const auto& var: *pInputs) {
198 if (var.active) {
199 activeVars.push_back(var);
200 }
201 }
202 return activeVars;
203 }
204
freeShaderVariableArray(uint32_t count,ST_ShaderVariable * vars)205 static void freeShaderVariableArray(uint32_t count, ST_ShaderVariable* vars) {
206 for (uint32_t i = 0; i < count; ++i) {
207 destroyShaderVariable(vars + i);
208 }
209 free(vars);
210 }
211
freeInterfaceBlockArray(uint32_t count,ST_InterfaceBlock * ibs)212 static void freeInterfaceBlockArray(uint32_t count, ST_InterfaceBlock* ibs) {
213 for (uint32_t i = 0; i < count; ++i) {
214 destroyInterfaceBlock(ibs + i);
215 }
216 free(ibs);
217 }
218
freeNameHashingMap(ST_NameHashingMap * nameHashingMap)219 static void freeNameHashingMap(ST_NameHashingMap* nameHashingMap) {
220 for (uint32_t i = 0; i < nameHashingMap->entryCount; ++i) {
221 free((void*)nameHashingMap->ppUserNames[i]);
222 free((void*)nameHashingMap->ppCompiledNames[i]);
223 }
224
225 free((void*)nameHashingMap->ppUserNames);
226 free((void*)nameHashingMap->ppCompiledNames);
227
228 free((void*)nameHashingMap);
229 }
230
destroyShaderVariable(ST_ShaderVariable * var)231 static void destroyShaderVariable(ST_ShaderVariable* var) {
232 free((void*)var->name);
233 free((void*)var->mappedName);
234
235 free((void*)var->pArraySizes);
236 freeShaderVariableArray(var->fieldsCount, var->pFields);
237
238 free((void*)var->structName);
239 }
240
destroyInterfaceBlock(ST_InterfaceBlock * ib)241 static void destroyInterfaceBlock(ST_InterfaceBlock* ib) {
242 free((void*)ib->name);
243 free((void*)ib->mappedName);
244 free((void*)ib->instanceName);
245
246 freeShaderVariableArray(ib->fieldsCount, ib->pFields);
247 }
248
249 } // namespace
250
251 extern "C" {
252
STInitialize()253 ANGLE_EXPORT void STInitialize() {
254 sh::Initialize();
255 }
256
STFinalize()257 ANGLE_EXPORT void STFinalize() {
258 sh::Finalize();
259 }
260
261 ANGLE_EXPORT ST_BuiltInResources*
STGenerateResources(ST_BuiltInResources * pResources)262 STGenerateResources(ST_BuiltInResources *pResources) {
263 static_assert(sizeof(ST_BuiltInResources) == sizeof(ShBuiltInResources),
264 "mismatch in ST_BuiltInResources versus ShBuiltInResources");
265 sh::InitBuiltInResources(reinterpret_cast<ShBuiltInResources*>(pResources));
266 return pResources;
267 }
268
STCompileAndResolve(const ST_ShaderCompileInfo * pInfo,ST_ShaderCompileResult ** ppResult)269 ANGLE_EXPORT void STCompileAndResolve(
270 const ST_ShaderCompileInfo* pInfo,
271 ST_ShaderCompileResult** ppResult) {
272
273 ShHandle handle = reinterpret_cast<ShHandle>(pInfo->inputHandle);
274
275 GLenum type = pInfo->type;
276 ST_ShaderSpec spec = pInfo->spec;
277 ST_ShaderOutput output = pInfo->output;
278 const ST_BuiltInResources* resources = pInfo->pResources;
279 const char* shaderString = pInfo->pShaderString;
280 ST_CompileOptions compileOptions = pInfo->compileOptions;
281
282 if (!handle) {
283 handle =
284 sh::ConstructCompiler(
285 type,
286 static_cast<ShShaderSpec>(spec),
287 static_cast<ShShaderOutput>(output),
288 reinterpret_cast<const ShBuiltInResources*>(resources));
289 }
290
291 (void)createNameHashingMap;
292 (void)createShaderVariableArray;
293 (void)createInterfaceBlockArray;
294
295 bool compileResult =
296 sh::Compile(
297 static_cast<ShHandle>(handle),
298 &shaderString, 1,
299 static_cast<ST_CompileOptions>(compileOptions));
300
301 ST_ShaderCompileResult* res =
302 (ST_ShaderCompileResult*)(malloc(sizeof(ST_ShaderCompileResult)));
303 memset(res, 0, sizeof(ST_ShaderCompileResult));
304
305 res->outputHandle = handle;
306
307 res->originalSource = strdup(shaderString);
308 res->translatedSource = toAllocedCString(sh::GetObjectCode(handle));
309 res->infoLog = toAllocedCString(sh::GetInfoLog(handle));
310
311 res->version = sh::GetShaderVersion(handle);
312
313 res->nameHashingMap = createNameHashingMap(*(sh::GetNameHashingMap(handle)));
314
315 initShaderVariableInfo(
316 sh::GetUniforms(handle), &res->uniformsCount,
317 (ST_ShaderVariable**)&res->pUniforms);
318 initInterfaceBlockInfo(
319 sh::GetUniformBlocks(handle), &res->uniformBlocksCount,
320 (ST_InterfaceBlock**)&res->pUniformBlocks);
321 initInterfaceBlockInfo(
322 sh::GetShaderStorageBlocks(handle), &res->shaderStorageBlocksCount,
323 (ST_InterfaceBlock**)&res->pShaderStorageBlocks);
324
325 const GLenum kShaderTypeVertex = 0x8b31;
326 const GLenum kShaderTypeFragment = 0x8b30;
327 const GLenum kShaderTypeCompute = 0x91b9;
328 const GLenum kShaderTypeGeometry = 0x8dd9;
329 const GLenum kShaderTypeTessControl = 0x8e88;
330 const GLenum kShaderTypeTessEval = 0x8e87;
331
332 switch (type) {
333 case kShaderTypeVertex: {
334
335 initShaderVariableInfo(
336 sh::GetOutputVaryings(handle), &res->outputVaryingsCount,
337 (ST_ShaderVariable**)&res->pOutputVaryings);
338 initShaderVariableInfo(
339 sh::GetAttributes(handle), &res->allAttributesCount,
340 (ST_ShaderVariable**)&res->pAllAttributes);
341
342 std::vector<sh::ShaderVariable> activeAttribs =
343 getActiveVariables(sh::GetAttributes(handle));
344 initShaderVariableInfo(
345 &activeAttribs, &res->activeAttributesCount,
346 (ST_ShaderVariable**)&res->pActiveAttributes);
347
348 res->numViews = sh::GetVertexShaderNumViews(handle);
349 break;
350 }
351 case kShaderTypeFragment: {
352 initShaderVariableInfo(
353 sh::GetAttributes(handle), &res->allAttributesCount,
354 (ST_ShaderVariable**)&res->pAllAttributes);
355
356 std::vector<sh::ShaderVariable> activeAttribs =
357 getActiveVariables(sh::GetAttributes(handle));
358 initShaderVariableInfo(
359 &activeAttribs, &res->activeAttributesCount,
360 (ST_ShaderVariable**)&res->pActiveAttributes);
361
362 // TODO(jmadill): These aren't sorted. Hope it works out?
363 initShaderVariableInfo(
364 sh::GetInputVaryings(handle),
365 &res->inputVaryingsCount,
366 (ST_ShaderVariable**)&res->pInputVaryings);
367
368 std::vector<sh::ShaderVariable> activeOutputVariables =
369 getActiveVariables(sh::GetOutputVariables(handle));
370 initShaderVariableInfo(
371 &activeOutputVariables, &res->activeOutputVariablesCount,
372 (ST_ShaderVariable**)&res->pActiveOutputVariables);
373
374 res->earlyFragmentTestsOptimization =
375 boolToUint(sh::HasEarlyFragmentTestsOptimization(handle));
376 break;
377 }
378 case kShaderTypeCompute: {
379 initShaderVariableInfo(
380 sh::GetAttributes(handle), &res->allAttributesCount,
381 (ST_ShaderVariable**)&res->pAllAttributes);
382 std::vector<sh::ShaderVariable> activeAttribs =
383 getActiveVariables(sh::GetAttributes(handle));
384 initShaderVariableInfo(
385 &activeAttribs, &res->activeAttributesCount,
386 (ST_ShaderVariable**)&res->pActiveAttributes);
387
388 sh::WorkGroupSize size = sh::GetComputeShaderLocalGroupSize(handle);
389 res->workGroupSize.localSizeQualifiers[0] = size[0];
390 res->workGroupSize.localSizeQualifiers[1] = size[1];
391 res->workGroupSize.localSizeQualifiers[2] = size[2];
392
393 res->sharedMemSize = sh::GetShaderSharedMemorySize(handle);
394 break;
395 }
396 case kShaderTypeGeometry: {
397 initShaderVariableInfo(
398 sh::GetInputVaryings(handle),
399 &res->inputVaryingsCount,
400 (ST_ShaderVariable**)&res->pInputVaryings);
401 initShaderVariableInfo(
402 sh::GetOutputVaryings(handle),
403 &res->outputVaryingsCount,
404 (ST_ShaderVariable**)&res->pOutputVaryings);
405
406 if (sh::HasValidGeometryShaderInputPrimitiveType(handle)) {
407 res->geometryShaderInputPrimitiveType =
408 sh::GetGeometryShaderInputPrimitiveType(handle);
409 }
410
411 if (sh::HasValidGeometryShaderOutputPrimitiveType(handle)) {
412 res->geometryShaderOutputPrimitiveType =
413 sh::GetGeometryShaderOutputPrimitiveType(handle);
414 }
415
416 if (sh::HasValidGeometryShaderMaxVertices(handle)) {
417 res->geometryShaderMaxVertices =
418 sh::GetGeometryShaderMaxVertices(handle);
419 }
420
421 res->geometryShaderInvocations =
422 sh::GetGeometryShaderInvocations(handle);
423 break;
424 }
425 case kShaderTypeTessControl: { // TODO
426 break;
427 }
428 case kShaderTypeTessEval: { // TODO
429 break;
430 }
431 default:
432 fprintf(stderr, "%s: unknown shader type: 0x%x\n", __func__, type);
433 abort();
434 break;
435 }
436
437 res->compileStatus = boolToUint(compileResult);
438 *ppResult = res;
439
440 sh::ClearResults(handle);
441 }
442
STFreeShaderResolveState(ST_ShaderCompileResult * state)443 ANGLE_EXPORT void STFreeShaderResolveState(
444 ST_ShaderCompileResult* state) {
445
446 free((void*)state->originalSource);
447 free((void*)state->translatedSource);
448 free((void*)state->infoLog);
449
450 freeNameHashingMap(state->nameHashingMap);
451
452 freeShaderVariableArray(state->inputVaryingsCount, (ST_ShaderVariable*)state->pInputVaryings);
453 freeShaderVariableArray(state->outputVaryingsCount, (ST_ShaderVariable*)state->pOutputVaryings);
454 freeShaderVariableArray(state->uniformsCount, (ST_ShaderVariable*)state->pUniforms);
455
456 freeInterfaceBlockArray(state->uniformBlocksCount, (ST_InterfaceBlock*)state->pUniformBlocks);
457 freeInterfaceBlockArray(state->shaderStorageBlocksCount, (ST_InterfaceBlock*)state->pShaderStorageBlocks);
458
459 freeShaderVariableArray(state->activeAttributesCount, (ST_ShaderVariable*)state->pActiveAttributes);
460 freeShaderVariableArray(state->allAttributesCount, (ST_ShaderVariable*)state->pAllAttributes);
461
462 freeShaderVariableArray(state->activeOutputVariablesCount, (ST_ShaderVariable*)state->pActiveOutputVariables);
463
464 free((void*)state);
465 }
466
STCopyVariable(const ST_ShaderVariable * pInput)467 ANGLE_EXPORT ST_ShaderVariable STCopyVariable(const ST_ShaderVariable* pInput) {
468 ST_ShaderVariable res = *pInput;
469
470 if (pInput->name) res.name = strdup(pInput->name);
471 if (pInput->mappedName) res.mappedName = strdup(pInput->mappedName);
472
473 res.pArraySizes = dupCArray(pInput->arraySizeCount, pInput->pArraySizes);
474 res.pFields = dupCArray(pInput->fieldsCount, pInput->pFields);
475
476 for (unsigned int i = 0; i < res.fieldsCount; ++i) {
477 res.pFields[i] = STCopyVariable(pInput->pFields + i);
478 }
479
480 if (pInput->structName) res.structName = strdup(pInput->structName);
481
482 return res;
483 }
484
STCopyInterfaceBlock(const ST_InterfaceBlock * pInput)485 ANGLE_EXPORT ST_InterfaceBlock STCopyInterfaceBlock(const ST_InterfaceBlock* pInput) {
486 ST_InterfaceBlock res = *pInput;
487
488 if (pInput->name) res.name = strdup(pInput->name);
489 if (pInput->mappedName) res.mappedName = strdup(pInput->mappedName);
490 if (pInput->instanceName) res.instanceName = strdup(pInput->instanceName);
491
492 res.pFields = dupCArray(pInput->fieldsCount, pInput->pFields);
493
494 for (unsigned int i = 0; i < res.fieldsCount; ++i) {
495 res.pFields[i] = STCopyVariable(pInput->pFields + i);
496 }
497
498 return res;
499 }
500
STDestroyVariable(ST_ShaderVariable * pInput)501 ANGLE_EXPORT void STDestroyVariable(ST_ShaderVariable* pInput) {
502 destroyShaderVariable(pInput);
503 }
504
STDestroyInterfaceBlock(ST_InterfaceBlock * pInput)505 ANGLE_EXPORT void STDestroyInterfaceBlock(ST_InterfaceBlock* pInput) {
506 destroyInterfaceBlock(pInput);
507 }
508
509 } // extern "C"
510