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/InitializeDll.h"
15#include "compiler/translator/length_limits.h"
16#include "compiler/translator/ShHandle.h"
17#include "compiler/translator/TranslatorHLSL.h"
18#include "compiler/translator/VariablePacker.h"
19
20static bool isInitialized = false;
21
22//
23// This is the platform independent interface between an OGL driver
24// and the shading language compiler.
25//
26
27static bool checkVariableMaxLengths(const ShHandle handle,
28                                    size_t expectedValue)
29{
30    size_t activeUniformLimit = 0;
31    ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit);
32    size_t activeAttribLimit = 0;
33    ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit);
34    size_t varyingLimit = 0;
35    ShGetInfo(handle, SH_VARYING_MAX_LENGTH, &varyingLimit);
36    return (expectedValue == activeUniformLimit &&
37            expectedValue == activeAttribLimit &&
38            expectedValue == varyingLimit);
39}
40
41static bool checkMappedNameMaxLength(const ShHandle handle, size_t expectedValue)
42{
43    size_t mappedNameMaxLength = 0;
44    ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength);
45    return (expectedValue == mappedNameMaxLength);
46}
47
48//
49// Driver must call this first, once, before doing any other compiler operations.
50// Subsequent calls to this function are no-op.
51//
52int ShInitialize()
53{
54    if (!isInitialized)
55    {
56        isInitialized = InitProcess();
57    }
58    return isInitialized ? 1 : 0;
59}
60
61//
62// Cleanup symbol tables
63//
64int ShFinalize()
65{
66    if (isInitialized)
67    {
68        DetachProcess();
69        isInitialized = false;
70    }
71    return 1;
72}
73
74//
75// Initialize built-in resources with minimum expected values.
76//
77void ShInitBuiltInResources(ShBuiltInResources* resources)
78{
79    // Constants.
80    resources->MaxVertexAttribs = 8;
81    resources->MaxVertexUniformVectors = 128;
82    resources->MaxVaryingVectors = 8;
83    resources->MaxVertexTextureImageUnits = 0;
84    resources->MaxCombinedTextureImageUnits = 8;
85    resources->MaxTextureImageUnits = 8;
86    resources->MaxFragmentUniformVectors = 16;
87    resources->MaxDrawBuffers = 1;
88
89    // Extensions.
90    resources->OES_standard_derivatives = 0;
91    resources->OES_EGL_image_external = 0;
92    resources->ARB_texture_rectangle = 0;
93    resources->EXT_draw_buffers = 0;
94    resources->EXT_frag_depth = 0;
95    resources->EXT_shader_texture_lod = 0;
96
97    // Disable highp precision in fragment shader by default.
98    resources->FragmentPrecisionHigh = 0;
99
100    // GLSL ES 3.0 constants.
101    resources->MaxVertexOutputVectors = 16;
102    resources->MaxFragmentInputVectors = 15;
103    resources->MinProgramTexelOffset = -8;
104    resources->MaxProgramTexelOffset = 7;
105
106    // Disable name hashing by default.
107    resources->HashFunction = NULL;
108
109    resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC;
110
111    resources->MaxExpressionComplexity = 256;
112    resources->MaxCallStackDepth = 256;
113}
114
115//
116// Driver calls these to create and destroy compiler objects.
117//
118ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec,
119                             ShShaderOutput output,
120                             const ShBuiltInResources* resources)
121{
122    TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output));
123    TCompiler* compiler = base->getAsCompiler();
124    if (compiler == 0)
125        return 0;
126
127    // Generate built-in symbol table.
128    if (!compiler->Init(*resources)) {
129        ShDestruct(base);
130        return 0;
131    }
132
133    return reinterpret_cast<void*>(base);
134}
135
136void ShDestruct(ShHandle handle)
137{
138    if (handle == 0)
139        return;
140
141    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
142
143    if (base->getAsCompiler())
144        DeleteCompiler(base->getAsCompiler());
145}
146
147void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, char *outString)
148{
149    if (!handle || !outString)
150    {
151        return;
152    }
153
154    TShHandleBase *base = static_cast<TShHandleBase*>(handle);
155    TCompiler *compiler = base->getAsCompiler();
156    if (!compiler)
157    {
158        return;
159    }
160
161    strncpy(outString, compiler->getBuiltInResourcesString().c_str(), outStringLen);
162    outString[outStringLen - 1] = '\0';
163}
164//
165// Do an actual compile on the given strings.  The result is left
166// in the given compile object.
167//
168// Return:  The return value of ShCompile is really boolean, indicating
169// success or failure.
170//
171int ShCompile(
172    const ShHandle handle,
173    const char* const shaderStrings[],
174    size_t numStrings,
175    int compileOptions)
176{
177    if (handle == 0)
178        return 0;
179
180    TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
181    TCompiler* compiler = base->getAsCompiler();
182    if (compiler == 0)
183        return 0;
184
185    bool success = compiler->compile(shaderStrings, numStrings, compileOptions);
186    return success ? 1 : 0;
187}
188
189void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params)
190{
191    if (!handle || !params)
192        return;
193
194    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
195    TCompiler* compiler = base->getAsCompiler();
196    if (!compiler) return;
197
198    switch(pname)
199    {
200    case SH_INFO_LOG_LENGTH:
201        *params = compiler->getInfoSink().info.size() + 1;
202        break;
203    case SH_OBJECT_CODE_LENGTH:
204        *params = compiler->getInfoSink().obj.size() + 1;
205        break;
206    case SH_ACTIVE_UNIFORMS:
207        *params = compiler->getUniforms().size();
208        break;
209    case SH_ACTIVE_UNIFORM_MAX_LENGTH:
210        *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
211        break;
212    case SH_ACTIVE_ATTRIBUTES:
213        *params = compiler->getAttribs().size();
214        break;
215    case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH:
216        *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
217        break;
218    case SH_VARYINGS:
219        *params = compiler->getVaryings().size();
220        break;
221    case SH_VARYING_MAX_LENGTH:
222        *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
223        break;
224    case SH_MAPPED_NAME_MAX_LENGTH:
225        // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to
226        // handle array and struct dereferences.
227        *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
228        break;
229    case SH_NAME_MAX_LENGTH:
230        *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
231        break;
232    case SH_HASHED_NAME_MAX_LENGTH:
233        if (compiler->getHashFunction() == NULL) {
234            *params = 0;
235        } else {
236            // 64 bits hashing output requires 16 bytes for hex
237            // representation.
238            const char HashedNamePrefix[] = HASHED_NAME_PREFIX;
239            (void)HashedNamePrefix;
240            *params = 16 + sizeof(HashedNamePrefix);
241        }
242        break;
243    case SH_HASHED_NAMES_COUNT:
244        *params = compiler->getNameMap().size();
245        break;
246    case SH_SHADER_VERSION:
247        *params = compiler->getShaderVersion();
248        break;
249    case SH_RESOURCES_STRING_LENGTH:
250        *params = compiler->getBuiltInResourcesString().length() + 1;
251        break;
252    case SH_OUTPUT_TYPE:
253        *params = compiler->getOutputType();
254        break;
255    default: UNREACHABLE();
256    }
257}
258
259//
260// Return any compiler log of messages for the application.
261//
262void ShGetInfoLog(const ShHandle handle, char* infoLog)
263{
264    if (!handle || !infoLog)
265        return;
266
267    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
268    TCompiler* compiler = base->getAsCompiler();
269    if (!compiler) return;
270
271    TInfoSink& infoSink = compiler->getInfoSink();
272    strcpy(infoLog, infoSink.info.c_str());
273}
274
275//
276// Return any object code.
277//
278void ShGetObjectCode(const ShHandle handle, char* objCode)
279{
280    if (!handle || !objCode)
281        return;
282
283    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
284    TCompiler* compiler = base->getAsCompiler();
285    if (!compiler) return;
286
287    TInfoSink& infoSink = compiler->getInfoSink();
288    strcpy(objCode, infoSink.obj.c_str());
289}
290
291void ShGetVariableInfo(const ShHandle handle,
292                       ShShaderInfo varType,
293                       int index,
294                       size_t* length,
295                       int* size,
296                       ShDataType* type,
297                       ShPrecisionType* precision,
298                       int* staticUse,
299                       char* name,
300                       char* mappedName)
301{
302    if (!handle || !size || !type || !precision || !staticUse || !name)
303        return;
304    ASSERT((varType == SH_ACTIVE_ATTRIBUTES) ||
305           (varType == SH_ACTIVE_UNIFORMS) ||
306           (varType == SH_VARYINGS));
307
308    TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
309    TCompiler* compiler = base->getAsCompiler();
310    if (compiler == 0)
311        return;
312
313    const TVariableInfoList& varList =
314        varType == SH_ACTIVE_ATTRIBUTES ? compiler->getAttribs() :
315            (varType == SH_ACTIVE_UNIFORMS ? compiler->getUniforms() :
316                compiler->getVaryings());
317    if (index < 0 || index >= static_cast<int>(varList.size()))
318        return;
319
320    const TVariableInfo& varInfo = varList[index];
321    if (length) *length = varInfo.name.size();
322    *size = varInfo.size;
323    *type = varInfo.type;
324    switch (varInfo.precision) {
325    case EbpLow:
326        *precision = SH_PRECISION_LOWP;
327        break;
328    case EbpMedium:
329        *precision = SH_PRECISION_MEDIUMP;
330        break;
331    case EbpHigh:
332        *precision = SH_PRECISION_HIGHP;
333        break;
334    default:
335        // Some types does not support precision, for example, boolean.
336        *precision = SH_PRECISION_UNDEFINED;
337        break;
338    }
339    *staticUse = varInfo.staticUse ? 1 : 0;
340
341    // This size must match that queried by
342    // SH_ACTIVE_UNIFORM_MAX_LENGTH, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, SH_VARYING_MAX_LENGTH
343    // in ShGetInfo, below.
344    size_t variableLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
345    ASSERT(checkVariableMaxLengths(handle, variableLength));
346    strncpy(name, varInfo.name.c_str(), variableLength);
347    name[variableLength - 1] = 0;
348    if (mappedName) {
349        // This size must match that queried by
350        // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below.
351        size_t maxMappedNameLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
352        ASSERT(checkMappedNameMaxLength(handle, maxMappedNameLength));
353        strncpy(mappedName, varInfo.mappedName.c_str(), maxMappedNameLength);
354        mappedName[maxMappedNameLength - 1] = 0;
355    }
356}
357
358void ShGetNameHashingEntry(const ShHandle handle,
359                           int index,
360                           char* name,
361                           char* hashedName)
362{
363    if (!handle || !name || !hashedName || index < 0)
364        return;
365
366    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
367    TCompiler* compiler = base->getAsCompiler();
368    if (!compiler) return;
369
370    const NameMap& nameMap = compiler->getNameMap();
371    if (index >= static_cast<int>(nameMap.size()))
372        return;
373
374    NameMap::const_iterator it = nameMap.begin();
375    for (int i = 0; i < index; ++i)
376        ++it;
377
378    size_t len = it->first.length() + 1;
379    size_t max_len = 0;
380    ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len);
381    if (len > max_len) {
382        ASSERT(false);
383        len = max_len;
384    }
385    strncpy(name, it->first.c_str(), len);
386    // To be on the safe side in case the source is longer than expected.
387    name[len - 1] = '\0';
388
389    len = it->second.length() + 1;
390    max_len = 0;
391    ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len);
392    if (len > max_len) {
393        ASSERT(false);
394        len = max_len;
395    }
396    strncpy(hashedName, it->second.c_str(), len);
397    // To be on the safe side in case the source is longer than expected.
398    hashedName[len - 1] = '\0';
399}
400
401void ShGetInfoPointer(const ShHandle handle, ShShaderInfo pname, void** params)
402{
403    if (!handle || !params)
404        return;
405
406    TShHandleBase* base = static_cast<TShHandleBase*>(handle);
407    TranslatorHLSL* translator = base->getAsTranslatorHLSL();
408    if (!translator) return;
409
410    switch(pname)
411    {
412    case SH_ACTIVE_UNIFORMS_ARRAY:
413        *params = (void*)&translator->getUniforms();
414        break;
415    case SH_ACTIVE_INTERFACE_BLOCKS_ARRAY:
416        *params = (void*)&translator->getInterfaceBlocks();
417        break;
418    case SH_ACTIVE_OUTPUT_VARIABLES_ARRAY:
419        *params = (void*)&translator->getOutputVariables();
420        break;
421    case SH_ACTIVE_ATTRIBUTES_ARRAY:
422        *params = (void*)&translator->getAttributes();
423        break;
424    case SH_ACTIVE_VARYINGS_ARRAY:
425        *params = (void*)&translator->getVaryings();
426        break;
427    default: UNREACHABLE();
428    }
429}
430
431int ShCheckVariablesWithinPackingLimits(
432    int maxVectors, ShVariableInfo* varInfoArray, size_t varInfoArraySize)
433{
434    if (varInfoArraySize == 0)
435        return 1;
436    ASSERT(varInfoArray);
437    TVariableInfoList variables;
438    for (size_t ii = 0; ii < varInfoArraySize; ++ii)
439    {
440        TVariableInfo var(varInfoArray[ii].type, varInfoArray[ii].size);
441        variables.push_back(var);
442    }
443    VariablePacker packer;
444    return packer.CheckVariablesWithinPackingLimits(maxVectors, variables) ? 1 : 0;
445}
446