1//
2// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Implement the top-level of interface to the compiler,
9// as defined in ShaderLang.h
10//
11
12#include "GLSLANG/ShaderLang.h"
13
14#include "compiler/translator/Compiler.h"
15#include "compiler/translator/InitializeDll.h"
16#include "compiler/translator/length_limits.h"
17#include "compiler/translator/TranslatorHLSL.h"
18#include "compiler/translator/VariablePacker.h"
19#include "angle_gl.h"
20
21namespace
22{
23
24enum ShaderVariableType
25{
26    SHADERVAR_UNIFORM,
27    SHADERVAR_VARYING,
28    SHADERVAR_ATTRIBUTE,
29    SHADERVAR_OUTPUTVARIABLE,
30    SHADERVAR_INTERFACEBLOCK
31};
32
33bool isInitialized = false;
34
35//
36// This is the platform independent interface between an OGL driver
37// and the shading language compiler.
38//
39
40static bool CheckVariableMaxLengths(const ShHandle handle,
41                                    size_t expectedValue)
42{
43    size_t activeUniformLimit = 0;
44    ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit);
45    size_t activeAttribLimit = 0;
46    ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit);
47    size_t varyingLimit = 0;
48    ShGetInfo(handle, SH_VARYING_MAX_LENGTH, &varyingLimit);
49    return (expectedValue == activeUniformLimit &&
50            expectedValue == activeAttribLimit &&
51            expectedValue == varyingLimit);
52}
53
54bool CheckMappedNameMaxLength(const ShHandle handle, size_t expectedValue)
55{
56    size_t mappedNameMaxLength = 0;
57    ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength);
58    return (expectedValue == mappedNameMaxLength);
59}
60
61template <typename VarT>
62const sh::ShaderVariable *ReturnVariable(const std::vector<VarT> &infoList, int index)
63{
64    if (index < 0 || static_cast<size_t>(index) >= infoList.size())
65    {
66        return NULL;
67    }
68
69    return &infoList[index];
70}
71
72const sh::ShaderVariable *GetVariable(const TCompiler *compiler, ShShaderInfo varType, int index)
73{
74    switch (varType)
75    {
76      case SH_ACTIVE_ATTRIBUTES:
77        return ReturnVariable(compiler->getAttributes(), index);
78      case SH_ACTIVE_UNIFORMS:
79        return ReturnVariable(compiler->getExpandedUniforms(), index);
80      case SH_VARYINGS:
81        return ReturnVariable(compiler->getExpandedVaryings(), index);
82      default:
83        UNREACHABLE();
84        return NULL;
85    }
86}
87
88ShPrecisionType ConvertPrecision(sh::GLenum precision)
89{
90    switch (precision)
91    {
92      case GL_HIGH_FLOAT:
93      case GL_HIGH_INT:
94        return SH_PRECISION_HIGHP;
95      case GL_MEDIUM_FLOAT:
96      case GL_MEDIUM_INT:
97        return SH_PRECISION_MEDIUMP;
98      case GL_LOW_FLOAT:
99      case GL_LOW_INT:
100        return SH_PRECISION_LOWP;
101      default:
102        return SH_PRECISION_UNDEFINED;
103    }
104}
105
106template <typename VarT>
107const std::vector<VarT> *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType);
108
109template <>
110const std::vector<sh::Uniform> *GetVariableList(const TCompiler *compiler, ShaderVariableType)
111{
112    return &compiler->getUniforms();
113}
114
115template <>
116const std::vector<sh::Varying> *GetVariableList(const TCompiler *compiler, ShaderVariableType)
117{
118    return &compiler->getVaryings();
119}
120
121template <>
122const std::vector<sh::Attribute> *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType)
123{
124    return (variableType == SHADERVAR_ATTRIBUTE ?
125        &compiler->getAttributes() :
126        &compiler->getOutputVariables());
127}
128
129template <>
130const std::vector<sh::InterfaceBlock> *GetVariableList(const TCompiler *compiler, ShaderVariableType)
131{
132    return &compiler->getInterfaceBlocks();
133}
134
135template <typename VarT>
136const std::vector<VarT> *GetShaderVariables(const ShHandle handle, ShaderVariableType variableType)
137{
138    if (!handle)
139    {
140        return NULL;
141    }
142
143    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
144    TCompiler* compiler = base->getAsCompiler();
145    if (!compiler)
146    {
147        return NULL;
148    }
149
150    return GetVariableList<VarT>(compiler, variableType);
151}
152
153}
154
155//
156// Driver must call this first, once, before doing any other compiler operations.
157// Subsequent calls to this function are no-op.
158//
159int ShInitialize()
160{
161    if (!isInitialized)
162    {
163        isInitialized = InitProcess();
164    }
165    return isInitialized ? 1 : 0;
166}
167
168//
169// Cleanup symbol tables
170//
171int ShFinalize()
172{
173    if (isInitialized)
174    {
175        DetachProcess();
176        isInitialized = false;
177    }
178    return 1;
179}
180
181//
182// Initialize built-in resources with minimum expected values.
183//
184void ShInitBuiltInResources(ShBuiltInResources* resources)
185{
186    // Constants.
187    resources->MaxVertexAttribs = 8;
188    resources->MaxVertexUniformVectors = 128;
189    resources->MaxVaryingVectors = 8;
190    resources->MaxVertexTextureImageUnits = 0;
191    resources->MaxCombinedTextureImageUnits = 8;
192    resources->MaxTextureImageUnits = 8;
193    resources->MaxFragmentUniformVectors = 16;
194    resources->MaxDrawBuffers = 1;
195
196    // Extensions.
197    resources->OES_standard_derivatives = 0;
198    resources->OES_EGL_image_external = 0;
199    resources->ARB_texture_rectangle = 0;
200    resources->EXT_draw_buffers = 0;
201    resources->EXT_frag_depth = 0;
202    resources->EXT_shader_texture_lod = 0;
203
204    // Disable highp precision in fragment shader by default.
205    resources->FragmentPrecisionHigh = 0;
206
207    // GLSL ES 3.0 constants.
208    resources->MaxVertexOutputVectors = 16;
209    resources->MaxFragmentInputVectors = 15;
210    resources->MinProgramTexelOffset = -8;
211    resources->MaxProgramTexelOffset = 7;
212
213    // Disable name hashing by default.
214    resources->HashFunction = NULL;
215
216    resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC;
217
218    resources->MaxExpressionComplexity = 256;
219    resources->MaxCallStackDepth = 256;
220}
221
222//
223// Driver calls these to create and destroy compiler objects.
224//
225ShHandle ShConstructCompiler(sh::GLenum type, ShShaderSpec spec,
226                             ShShaderOutput output,
227                             const ShBuiltInResources* resources)
228{
229    TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output));
230    TCompiler* compiler = base->getAsCompiler();
231    if (compiler == 0)
232        return 0;
233
234    // Generate built-in symbol table.
235    if (!compiler->Init(*resources)) {
236        ShDestruct(base);
237        return 0;
238    }
239
240    return reinterpret_cast<void*>(base);
241}
242
243void ShDestruct(ShHandle handle)
244{
245    if (handle == 0)
246        return;
247
248    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
249
250    if (base->getAsCompiler())
251        DeleteCompiler(base->getAsCompiler());
252}
253
254void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, char *outString)
255{
256    if (!handle || !outString)
257    {
258        return;
259    }
260
261    TShHandleBase *base = static_cast<TShHandleBase*>(handle);
262    TCompiler *compiler = base->getAsCompiler();
263    if (!compiler)
264    {
265        return;
266    }
267
268    strncpy(outString, compiler->getBuiltInResourcesString().c_str(), outStringLen);
269    outString[outStringLen - 1] = '\0';
270}
271//
272// Do an actual compile on the given strings.  The result is left
273// in the given compile object.
274//
275// Return:  The return value of ShCompile is really boolean, indicating
276// success or failure.
277//
278int ShCompile(
279    const ShHandle handle,
280    const char* const shaderStrings[],
281    size_t numStrings,
282    int compileOptions)
283{
284    if (handle == 0)
285        return 0;
286
287    TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
288    TCompiler* compiler = base->getAsCompiler();
289    if (compiler == 0)
290        return 0;
291
292    bool success = compiler->compile(shaderStrings, numStrings, compileOptions);
293    return success ? 1 : 0;
294}
295
296void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params)
297{
298    if (!handle || !params)
299        return;
300
301    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
302    TCompiler* compiler = base->getAsCompiler();
303    if (!compiler) return;
304
305    switch(pname)
306    {
307    case SH_INFO_LOG_LENGTH:
308        *params = compiler->getInfoSink().info.size() + 1;
309        break;
310    case SH_OBJECT_CODE_LENGTH:
311        *params = compiler->getInfoSink().obj.size() + 1;
312        break;
313    case SH_ACTIVE_UNIFORMS:
314        *params = compiler->getExpandedUniforms().size();
315        break;
316    case SH_ACTIVE_UNIFORM_MAX_LENGTH:
317        *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
318        break;
319    case SH_ACTIVE_ATTRIBUTES:
320        *params = compiler->getAttributes().size();
321        break;
322    case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH:
323        *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
324        break;
325    case SH_VARYINGS:
326        *params = compiler->getExpandedVaryings().size();
327        break;
328    case SH_VARYING_MAX_LENGTH:
329        *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
330        break;
331    case SH_MAPPED_NAME_MAX_LENGTH:
332        // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to
333        // handle array and struct dereferences.
334        *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
335        break;
336    case SH_NAME_MAX_LENGTH:
337        *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
338        break;
339    case SH_HASHED_NAME_MAX_LENGTH:
340        if (compiler->getHashFunction() == NULL) {
341            *params = 0;
342        } else {
343            // 64 bits hashing output requires 16 bytes for hex
344            // representation.
345            const char HashedNamePrefix[] = HASHED_NAME_PREFIX;
346            (void)HashedNamePrefix;
347            *params = 16 + sizeof(HashedNamePrefix);
348        }
349        break;
350    case SH_HASHED_NAMES_COUNT:
351        *params = compiler->getNameMap().size();
352        break;
353    case SH_SHADER_VERSION:
354        *params = compiler->getShaderVersion();
355        break;
356    case SH_RESOURCES_STRING_LENGTH:
357        *params = compiler->getBuiltInResourcesString().length() + 1;
358        break;
359    case SH_OUTPUT_TYPE:
360        *params = compiler->getOutputType();
361        break;
362    default: UNREACHABLE();
363    }
364}
365
366//
367// Return any compiler log of messages for the application.
368//
369void ShGetInfoLog(const ShHandle handle, char* infoLog)
370{
371    if (!handle || !infoLog)
372        return;
373
374    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
375    TCompiler* compiler = base->getAsCompiler();
376    if (!compiler) return;
377
378    TInfoSink& infoSink = compiler->getInfoSink();
379    strcpy(infoLog, infoSink.info.c_str());
380}
381
382//
383// Return any object code.
384//
385void ShGetObjectCode(const ShHandle handle, char* objCode)
386{
387    if (!handle || !objCode)
388        return;
389
390    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
391    TCompiler* compiler = base->getAsCompiler();
392    if (!compiler) return;
393
394    TInfoSink& infoSink = compiler->getInfoSink();
395    strcpy(objCode, infoSink.obj.c_str());
396}
397
398void ShGetVariableInfo(const ShHandle handle,
399                       ShShaderInfo varType,
400                       int index,
401                       size_t* length,
402                       int* size,
403                       sh::GLenum* type,
404                       ShPrecisionType* precision,
405                       int* staticUse,
406                       char* name,
407                       char* mappedName)
408{
409    if (!handle || !size || !type || !precision || !staticUse || !name)
410        return;
411    ASSERT((varType == SH_ACTIVE_ATTRIBUTES) ||
412           (varType == SH_ACTIVE_UNIFORMS) ||
413           (varType == SH_VARYINGS));
414
415    TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
416    TCompiler* compiler = base->getAsCompiler();
417    if (compiler == 0)
418        return;
419
420    const sh::ShaderVariable *varInfo = GetVariable(compiler, varType, index);
421    if (!varInfo)
422    {
423        return;
424    }
425
426    if (length) *length = varInfo->name.size();
427    *size = varInfo->elementCount();
428    *type = varInfo->type;
429    *precision = ConvertPrecision(varInfo->precision);
430    *staticUse = varInfo->staticUse ? 1 : 0;
431
432    // This size must match that queried by
433    // SH_ACTIVE_UNIFORM_MAX_LENGTH, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, SH_VARYING_MAX_LENGTH
434    // in ShGetInfo, below.
435    size_t variableLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
436    ASSERT(CheckVariableMaxLengths(handle, variableLength));
437    strncpy(name, varInfo->name.c_str(), variableLength);
438    name[variableLength - 1] = 0;
439    if (mappedName)
440    {
441        // This size must match that queried by
442        // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below.
443        size_t maxMappedNameLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
444        ASSERT(CheckMappedNameMaxLength(handle, maxMappedNameLength));
445        strncpy(mappedName, varInfo->mappedName.c_str(), maxMappedNameLength);
446        mappedName[maxMappedNameLength - 1] = 0;
447    }
448}
449
450void ShGetNameHashingEntry(const ShHandle handle,
451                           int index,
452                           char* name,
453                           char* hashedName)
454{
455    if (!handle || !name || !hashedName || index < 0)
456        return;
457
458    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
459    TCompiler* compiler = base->getAsCompiler();
460    if (!compiler) return;
461
462    const NameMap& nameMap = compiler->getNameMap();
463    if (index >= static_cast<int>(nameMap.size()))
464        return;
465
466    NameMap::const_iterator it = nameMap.begin();
467    for (int i = 0; i < index; ++i)
468        ++it;
469
470    size_t len = it->first.length() + 1;
471    size_t max_len = 0;
472    ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len);
473    if (len > max_len) {
474        ASSERT(false);
475        len = max_len;
476    }
477    strncpy(name, it->first.c_str(), len);
478    // To be on the safe side in case the source is longer than expected.
479    name[len - 1] = '\0';
480
481    len = it->second.length() + 1;
482    max_len = 0;
483    ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len);
484    if (len > max_len) {
485        ASSERT(false);
486        len = max_len;
487    }
488    strncpy(hashedName, it->second.c_str(), len);
489    // To be on the safe side in case the source is longer than expected.
490    hashedName[len - 1] = '\0';
491}
492
493const std::vector<sh::Uniform> *ShGetUniforms(const ShHandle handle)
494{
495    return GetShaderVariables<sh::Uniform>(handle, SHADERVAR_UNIFORM);
496}
497
498const std::vector<sh::Varying> *ShGetVaryings(const ShHandle handle)
499{
500    return GetShaderVariables<sh::Varying>(handle, SHADERVAR_VARYING);
501}
502
503const std::vector<sh::Attribute> *ShGetAttributes(const ShHandle handle)
504{
505    return GetShaderVariables<sh::Attribute>(handle, SHADERVAR_ATTRIBUTE);
506}
507
508const std::vector<sh::Attribute> *ShGetOutputVariables(const ShHandle handle)
509{
510    return GetShaderVariables<sh::Attribute>(handle, SHADERVAR_OUTPUTVARIABLE);
511}
512
513const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handle)
514{
515    return GetShaderVariables<sh::InterfaceBlock>(handle, SHADERVAR_INTERFACEBLOCK);
516}
517
518int ShCheckVariablesWithinPackingLimits(
519    int maxVectors, ShVariableInfo* varInfoArray, size_t varInfoArraySize)
520{
521    if (varInfoArraySize == 0)
522        return 1;
523    ASSERT(varInfoArray);
524    std::vector<sh::ShaderVariable> variables;
525    for (size_t ii = 0; ii < varInfoArraySize; ++ii)
526    {
527        sh::ShaderVariable var(varInfoArray[ii].type, varInfoArray[ii].size);
528        variables.push_back(var);
529    }
530    VariablePacker packer;
531    return packer.CheckVariablesWithinPackingLimits(maxVectors, variables) ? 1 : 0;
532}
533
534bool ShGetInterfaceBlockRegister(const ShHandle handle,
535                                 const char *interfaceBlockName,
536                                 unsigned int *indexOut)
537{
538    if (!handle || !interfaceBlockName || !indexOut)
539    {
540        return false;
541    }
542
543    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
544    TranslatorHLSL* translator = base->getAsTranslatorHLSL();
545    if (!translator)
546    {
547        return false;
548    }
549
550    if (!translator->hasInterfaceBlock(interfaceBlockName))
551    {
552        return false;
553    }
554
555    *indexOut = translator->getInterfaceBlockRegister(interfaceBlockName);
556    return true;
557}
558
559bool ShGetUniformRegister(const ShHandle handle,
560                          const char *uniformName,
561                          unsigned int *indexOut)
562{
563    if (!handle || !uniformName || !indexOut)
564    {
565        return false;
566    }
567
568    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
569    TranslatorHLSL* translator = base->getAsTranslatorHLSL();
570    if (!translator)
571    {
572        return false;
573    }
574
575    if (!translator->hasUniform(uniformName))
576    {
577        return false;
578    }
579
580    *indexOut = translator->getUniformRegister(uniformName);
581    return true;
582}
583