blob: 35dac5f088a42f34b5d609648a439c0b7fb52f22 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +00002// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
alokp@chromium.org774d7062010-07-21 18:55:45 +00008// Implement the top-level of interface to the compiler,
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00009// as defined in ShaderLang.h
10//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000011
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000012#include "GLSLANG/ShaderLang.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000013
Jamie Madilld4a3a312014-06-25 16:04:56 -040014#include "compiler/translator/Compiler.h"
Geoff Lang17732822013-08-29 13:46:49 -040015#include "compiler/translator/InitializeDll.h"
Jamie Madill5508f392014-02-20 13:31:36 -050016#include "compiler/translator/length_limits.h"
Geoff Lang17732822013-08-29 13:46:49 -040017#include "compiler/translator/TranslatorHLSL.h"
18#include "compiler/translator/VariablePacker.h"
Jamie Madilla718c1e2014-07-02 15:31:22 -040019#include "angle_gl.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000020
Jamie Madille294bb82014-07-17 14:16:26 -040021namespace
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;
Jamie Madillb4d192c2014-02-26 09:54:10 -050034
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000035//
36// This is the platform independent interface between an OGL driver
alokp@chromium.org774d7062010-07-21 18:55:45 +000037// and the shading language compiler.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000038//
39
Jamie Madille294bb82014-07-17 14:16:26 -040040template <typename VarT>
41const std::vector<VarT> *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType);
42
43template <>
44const std::vector<sh::Uniform> *GetVariableList(const TCompiler *compiler, ShaderVariableType)
45{
46 return &compiler->getUniforms();
47}
48
49template <>
50const std::vector<sh::Varying> *GetVariableList(const TCompiler *compiler, ShaderVariableType)
51{
52 return &compiler->getVaryings();
53}
54
55template <>
56const std::vector<sh::Attribute> *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType)
57{
58 return (variableType == SHADERVAR_ATTRIBUTE ?
59 &compiler->getAttributes() :
60 &compiler->getOutputVariables());
61}
62
63template <>
64const std::vector<sh::InterfaceBlock> *GetVariableList(const TCompiler *compiler, ShaderVariableType)
65{
66 return &compiler->getInterfaceBlocks();
67}
68
69template <typename VarT>
70const std::vector<VarT> *GetShaderVariables(const ShHandle handle, ShaderVariableType variableType)
71{
72 if (!handle)
73 {
74 return NULL;
75 }
76
77 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
78 TCompiler* compiler = base->getAsCompiler();
79 if (!compiler)
80 {
81 return NULL;
82 }
83
84 return GetVariableList<VarT>(compiler, variableType);
85}
86
87}
88
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000089//
Alok Priyadarshib11713f2013-08-01 16:02:39 -070090// Driver must call this first, once, before doing any other compiler operations.
91// Subsequent calls to this function are no-op.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000092//
93int ShInitialize()
94{
Jamie Madill477bc782014-02-26 09:54:17 -050095 if (!isInitialized)
96 {
97 isInitialized = InitProcess();
98 }
Jamie Madillb4d192c2014-02-26 09:54:10 -050099 return isInitialized ? 1 : 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000100}
101
102//
alokp@chromium.org94a86ad2010-08-25 20:02:11 +0000103// Cleanup symbol tables
104//
105int ShFinalize()
106{
Geoff Langf20f0202014-04-28 11:02:07 -0400107 if (isInitialized)
108 {
109 DetachProcess();
110 isInitialized = false;
111 }
alokp@chromium.org94a86ad2010-08-25 20:02:11 +0000112 return 1;
113}
114
115//
116// Initialize built-in resources with minimum expected values.
117//
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000118void ShInitBuiltInResources(ShBuiltInResources* resources)
alokp@chromium.org94a86ad2010-08-25 20:02:11 +0000119{
Kimmo Kinnunen7c1cfd62014-10-15 14:59:57 +0300120 // Make comparable.
121 memset(resources, 0, sizeof(*resources));
122
alokp@chromium.org94a86ad2010-08-25 20:02:11 +0000123 // Constants.
124 resources->MaxVertexAttribs = 8;
125 resources->MaxVertexUniformVectors = 128;
126 resources->MaxVaryingVectors = 8;
127 resources->MaxVertexTextureImageUnits = 0;
128 resources->MaxCombinedTextureImageUnits = 8;
129 resources->MaxTextureImageUnits = 8;
130 resources->MaxFragmentUniformVectors = 16;
131 resources->MaxDrawBuffers = 1;
132
133 // Extensions.
134 resources->OES_standard_derivatives = 0;
zmo@google.com09c323a2011-08-12 18:22:25 +0000135 resources->OES_EGL_image_external = 0;
kbr@chromium.org205fef32011-11-22 20:50:02 +0000136 resources->ARB_texture_rectangle = 0;
shannon.woods@transgaming.com550cd092013-02-28 23:19:54 +0000137 resources->EXT_draw_buffers = 0;
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400138 resources->EXT_frag_depth = 0;
Nicolas Capens46485082014-04-15 13:12:50 -0400139 resources->EXT_shader_texture_lod = 0;
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000140
Olli Etuahoe61209a2014-09-26 12:01:17 +0300141 resources->NV_draw_buffers = 0;
142
shannon.woods%transgaming.com@gtempaccount.comcbb6b6a2013-04-13 03:27:47 +0000143 // Disable highp precision in fragment shader by default.
144 resources->FragmentPrecisionHigh = 0;
145
shannonwoods@chromium.org74b86cf2013-05-30 00:02:58 +0000146 // GLSL ES 3.0 constants.
147 resources->MaxVertexOutputVectors = 16;
148 resources->MaxFragmentInputVectors = 15;
149 resources->MinProgramTexelOffset = -8;
150 resources->MaxProgramTexelOffset = 7;
151
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000152 // Disable name hashing by default.
153 resources->HashFunction = NULL;
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000154
155 resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC;
Nicolas Capens7d649a02014-02-07 11:24:32 -0500156
157 resources->MaxExpressionComplexity = 256;
158 resources->MaxCallStackDepth = 256;
alokp@chromium.org94a86ad2010-08-25 20:02:11 +0000159}
160
161//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000162// Driver calls these to create and destroy compiler objects.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000163//
Jamie Madill183bde52014-07-02 15:31:19 -0400164ShHandle ShConstructCompiler(sh::GLenum type, ShShaderSpec spec,
zmo@google.com5601ea02011-06-10 18:23:25 +0000165 ShShaderOutput output,
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000166 const ShBuiltInResources* resources)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000167{
zmo@google.com5601ea02011-06-10 18:23:25 +0000168 TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output));
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000169 TCompiler* compiler = base->getAsCompiler();
170 if (compiler == 0)
171 return 0;
172
173 // Generate built-in symbol table.
alokp@chromium.org07620a52010-09-23 17:53:56 +0000174 if (!compiler->Init(*resources)) {
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000175 ShDestruct(base);
176 return 0;
177 }
178
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179 return reinterpret_cast<void*>(base);
180}
181
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182void ShDestruct(ShHandle handle)
183{
184 if (handle == 0)
185 return;
186
187 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
188
189 if (base->getAsCompiler())
190 DeleteCompiler(base->getAsCompiler());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000191}
192
Shannon Woods2d76e5f2014-05-16 17:46:41 -0400193void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, char *outString)
194{
195 if (!handle || !outString)
196 {
197 return;
198 }
199
200 TShHandleBase *base = static_cast<TShHandleBase*>(handle);
201 TCompiler *compiler = base->getAsCompiler();
202 if (!compiler)
203 {
204 return;
205 }
206
207 strncpy(outString, compiler->getBuiltInResourcesString().c_str(), outStringLen);
208 outString[outStringLen - 1] = '\0';
209}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210//
Shannon Woods2d76e5f2014-05-16 17:46:41 -0400211// Do an actual compile on the given strings. The result is left
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000212// in the given compile object.
213//
214// Return: The return value of ShCompile is really boolean, indicating
215// success or failure.
216//
217int ShCompile(
218 const ShHandle handle,
219 const char* const shaderStrings[],
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000220 size_t numStrings,
alokp@chromium.org7beea402010-09-15 21:18:34 +0000221 int compileOptions)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000222{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223 if (handle == 0)
224 return 0;
225
226 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
227 TCompiler* compiler = base->getAsCompiler();
228 if (compiler == 0)
229 return 0;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000230
alokp@chromium.org07620a52010-09-23 17:53:56 +0000231 bool success = compiler->compile(shaderStrings, numStrings, compileOptions);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000232 return success ? 1 : 0;
233}
234
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000235void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params)
alokp@chromium.org7beea402010-09-15 21:18:34 +0000236{
237 if (!handle || !params)
238 return;
239
240 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
241 TCompiler* compiler = base->getAsCompiler();
242 if (!compiler) return;
243
244 switch(pname)
245 {
246 case SH_INFO_LOG_LENGTH:
247 *params = compiler->getInfoSink().info.size() + 1;
248 break;
249 case SH_OBJECT_CODE_LENGTH:
250 *params = compiler->getInfoSink().obj.size() + 1;
251 break;
zmo@google.comfd747b82011-04-23 01:30:07 +0000252 case SH_MAPPED_NAME_MAX_LENGTH:
kbr@chromium.org22152112011-10-26 01:18:28 +0000253 // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to
254 // handle array and struct dereferences.
Zhenyao Mo7faf1a12014-04-25 18:03:56 -0700255 *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
zmo@google.comfd747b82011-04-23 01:30:07 +0000256 break;
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000257 case SH_NAME_MAX_LENGTH:
Zhenyao Mo7faf1a12014-04-25 18:03:56 -0700258 *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000259 break;
260 case SH_HASHED_NAME_MAX_LENGTH:
261 if (compiler->getHashFunction() == NULL) {
262 *params = 0;
263 } else {
264 // 64 bits hashing output requires 16 bytes for hex
265 // representation.
266 const char HashedNamePrefix[] = HASHED_NAME_PREFIX;
Geoff Langcebb5aa2014-04-07 14:13:40 -0400267 (void)HashedNamePrefix;
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000268 *params = 16 + sizeof(HashedNamePrefix);
269 }
270 break;
271 case SH_HASHED_NAMES_COUNT:
272 *params = compiler->getNameMap().size();
273 break;
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000274 case SH_SHADER_VERSION:
275 *params = compiler->getShaderVersion();
276 break;
Shannon Woods2d76e5f2014-05-16 17:46:41 -0400277 case SH_RESOURCES_STRING_LENGTH:
278 *params = compiler->getBuiltInResourcesString().length() + 1;
279 break;
Jamie Madill68fe74a2014-05-27 12:56:01 -0400280 case SH_OUTPUT_TYPE:
281 *params = compiler->getOutputType();
282 break;
alokp@chromium.org7beea402010-09-15 21:18:34 +0000283 default: UNREACHABLE();
284 }
285}
286
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000287//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000288// Return any compiler log of messages for the application.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000289//
alokp@chromium.org7beea402010-09-15 21:18:34 +0000290void ShGetInfoLog(const ShHandle handle, char* infoLog)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000291{
alokp@chromium.org7beea402010-09-15 21:18:34 +0000292 if (!handle || !infoLog)
293 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000294
295 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000296 TCompiler* compiler = base->getAsCompiler();
297 if (!compiler) return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000298
alokp@chromium.org7beea402010-09-15 21:18:34 +0000299 TInfoSink& infoSink = compiler->getInfoSink();
300 strcpy(infoLog, infoSink.info.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000301}
302
303//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000304// Return any object code.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000305//
alokp@chromium.org7beea402010-09-15 21:18:34 +0000306void ShGetObjectCode(const ShHandle handle, char* objCode)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000307{
alokp@chromium.org7beea402010-09-15 21:18:34 +0000308 if (!handle || !objCode)
309 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000310
311 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000312 TCompiler* compiler = base->getAsCompiler();
313 if (!compiler) return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000314
alokp@chromium.org7beea402010-09-15 21:18:34 +0000315 TInfoSink& infoSink = compiler->getInfoSink();
316 strcpy(objCode, infoSink.obj.c_str());
317}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000318
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000319void ShGetNameHashingEntry(const ShHandle handle,
320 int index,
321 char* name,
322 char* hashedName)
323{
324 if (!handle || !name || !hashedName || index < 0)
325 return;
326
327 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
328 TCompiler* compiler = base->getAsCompiler();
329 if (!compiler) return;
330
331 const NameMap& nameMap = compiler->getNameMap();
332 if (index >= static_cast<int>(nameMap.size()))
333 return;
334
335 NameMap::const_iterator it = nameMap.begin();
336 for (int i = 0; i < index; ++i)
337 ++it;
338
339 size_t len = it->first.length() + 1;
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000340 size_t max_len = 0;
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000341 ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len);
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000342 if (len > max_len) {
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000343 ASSERT(false);
344 len = max_len;
345 }
346 strncpy(name, it->first.c_str(), len);
347 // To be on the safe side in case the source is longer than expected.
daniel@transgaming.com75cb6892013-02-01 03:20:26 +0000348 name[len - 1] = '\0';
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000349
350 len = it->second.length() + 1;
351 max_len = 0;
352 ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len);
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000353 if (len > max_len) {
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000354 ASSERT(false);
355 len = max_len;
356 }
357 strncpy(hashedName, it->second.c_str(), len);
358 // To be on the safe side in case the source is longer than expected.
daniel@transgaming.com75cb6892013-02-01 03:20:26 +0000359 hashedName[len - 1] = '\0';
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000360}
daniel@transgaming.com043da132012-12-20 21:12:22 +0000361
Jamie Madille294bb82014-07-17 14:16:26 -0400362const std::vector<sh::Uniform> *ShGetUniforms(const ShHandle handle)
daniel@transgaming.com043da132012-12-20 21:12:22 +0000363{
Jamie Madille294bb82014-07-17 14:16:26 -0400364 return GetShaderVariables<sh::Uniform>(handle, SHADERVAR_UNIFORM);
365}
daniel@transgaming.com043da132012-12-20 21:12:22 +0000366
Jamie Madille294bb82014-07-17 14:16:26 -0400367const std::vector<sh::Varying> *ShGetVaryings(const ShHandle handle)
368{
369 return GetShaderVariables<sh::Varying>(handle, SHADERVAR_VARYING);
370}
daniel@transgaming.com043da132012-12-20 21:12:22 +0000371
Jamie Madille294bb82014-07-17 14:16:26 -0400372const std::vector<sh::Attribute> *ShGetAttributes(const ShHandle handle)
373{
374 return GetShaderVariables<sh::Attribute>(handle, SHADERVAR_ATTRIBUTE);
375}
376
377const std::vector<sh::Attribute> *ShGetOutputVariables(const ShHandle handle)
378{
379 return GetShaderVariables<sh::Attribute>(handle, SHADERVAR_OUTPUTVARIABLE);
380}
381
382const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handle)
383{
384 return GetShaderVariables<sh::InterfaceBlock>(handle, SHADERVAR_INTERFACEBLOCK);
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000385}
Zhenyao Moa15f3e82013-09-23 14:57:08 -0400386
387int ShCheckVariablesWithinPackingLimits(
388 int maxVectors, ShVariableInfo* varInfoArray, size_t varInfoArraySize)
389{
390 if (varInfoArraySize == 0)
391 return 1;
392 ASSERT(varInfoArray);
Jamie Madilla718c1e2014-07-02 15:31:22 -0400393 std::vector<sh::ShaderVariable> variables;
Zhenyao Moa15f3e82013-09-23 14:57:08 -0400394 for (size_t ii = 0; ii < varInfoArraySize; ++ii)
395 {
Jamie Madilla3fe2b42014-07-18 10:33:13 -0400396 sh::ShaderVariable var(varInfoArray[ii].type, varInfoArray[ii].size);
Zhenyao Moa15f3e82013-09-23 14:57:08 -0400397 variables.push_back(var);
398 }
399 VariablePacker packer;
400 return packer.CheckVariablesWithinPackingLimits(maxVectors, variables) ? 1 : 0;
401}
Jamie Madill4e1fd412014-07-10 17:50:10 -0400402
403bool ShGetInterfaceBlockRegister(const ShHandle handle,
404 const char *interfaceBlockName,
405 unsigned int *indexOut)
406{
407 if (!handle || !interfaceBlockName || !indexOut)
408 {
409 return false;
410 }
411
412 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
413 TranslatorHLSL* translator = base->getAsTranslatorHLSL();
414 if (!translator)
415 {
416 return false;
417 }
418
419 if (!translator->hasInterfaceBlock(interfaceBlockName))
420 {
421 return false;
422 }
423
424 *indexOut = translator->getInterfaceBlockRegister(interfaceBlockName);
425 return true;
426}
Jamie Madill9fe25e92014-07-18 10:33:08 -0400427
428bool ShGetUniformRegister(const ShHandle handle,
429 const char *uniformName,
430 unsigned int *indexOut)
431{
432 if (!handle || !uniformName || !indexOut)
433 {
434 return false;
435 }
436
437 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
438 TranslatorHLSL* translator = base->getAsTranslatorHLSL();
439 if (!translator)
440 {
441 return false;
442 }
443
444 if (!translator->hasUniform(uniformName))
445 {
446 return false;
447 }
448
449 *indexOut = translator->getUniformRegister(uniformName);
450 return true;
451}