blob: 2c58e2d8fe85c7cc56f85314a0b6658b011aee89 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
daniel@transgaming.com2cdf8332012-02-17 18:00:50 +00002// Copyright (c) 2002-2012 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// Shader.cpp: Implements the gl::Shader class and its derived classes
8// VertexShader and FragmentShader. Implements GL shader objects and related
9// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84.
10
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011#include "libGLESv2/Shader.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
alokp@chromium.org91b72322010-06-02 15:50:56 +000013#include <string>
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000014
alokp@chromium.org91b72322010-06-02 15:50:56 +000015#include "GLSLANG/Shaderlang.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000016#include "libGLESv2/main.h"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000017#include "libGLESv2/utilities.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000018
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000019namespace gl
20{
21void *Shader::mFragmentCompiler = NULL;
22void *Shader::mVertexCompiler = NULL;
23
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000024Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000025{
26 mSource = NULL;
27 mHlsl = NULL;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000028 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000029
30 // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler)
31 if (!mFragmentCompiler)
32 {
33 int result = ShInitialize();
34
35 if (result)
36 {
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000037 ShBuiltInResources resources;
38 ShInitBuiltInResources(&resources);
zmo@google.com5601ea02011-06-10 18:23:25 +000039 Context *context = getContext();
daniel@transgaming.com396c6432010-11-26 16:26:12 +000040
alokp@chromium.org94a86ad2010-08-25 20:02:11 +000041 resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
42 resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
daniel@transgaming.com396c6432010-11-26 16:26:12 +000043 resources.MaxVaryingVectors = context->getMaximumVaryingVectors();
daniel@transgaming.comaf29cac2011-05-11 15:36:31 +000044 resources.MaxVertexTextureImageUnits = context->getMaximumVertexTextureImageUnits();
45 resources.MaxCombinedTextureImageUnits = context->getMaximumCombinedTextureImageUnits();
alokp@chromium.org94a86ad2010-08-25 20:02:11 +000046 resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
daniel@transgaming.com458da142010-11-28 02:03:02 +000047 resources.MaxFragmentUniformVectors = context->getMaximumFragmentUniformVectors();
alokp@chromium.org94a86ad2010-08-25 20:02:11 +000048 resources.MaxDrawBuffers = MAX_DRAW_BUFFERS;
alokp@chromium.orgd303ef92010-09-09 17:30:15 +000049 resources.OES_standard_derivatives = 1;
apatrick@chromium.org65756022012-01-17 21:45:38 +000050 // resources.OES_EGL_image_external = getDisplay()->isD3d9ExDevice() ? 1 : 0; // TODO: commented out until the extension is actually supported.
alokp@chromium.orge4249f02010-07-26 18:13:52 +000051
zmo@google.com5601ea02011-06-10 18:23:25 +000052 mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources);
53 mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000054 }
55 }
56
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000057 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000058 mDeleteStatus = false;
59}
60
61Shader::~Shader()
62{
63 delete[] mSource;
64 delete[] mHlsl;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000065 delete[] mInfoLog;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000066}
67
daniel@transgaming.com6c785212010-03-30 03:36:17 +000068GLuint Shader::getHandle() const
69{
70 return mHandle;
71}
72
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000073void Shader::setSource(GLsizei count, const char **string, const GLint *length)
74{
75 delete[] mSource;
76 int totalLength = 0;
77
78 for (int i = 0; i < count; i++)
79 {
80 if (length && length[i] >= 0)
81 {
82 totalLength += length[i];
83 }
84 else
85 {
86 totalLength += (int)strlen(string[i]);
87 }
88 }
89
90 mSource = new char[totalLength + 1];
91 char *code = mSource;
92
93 for (int i = 0; i < count; i++)
94 {
95 int stringLength;
96
97 if (length && length[i] >= 0)
98 {
99 stringLength = length[i];
100 }
101 else
102 {
103 stringLength = (int)strlen(string[i]);
104 }
105
106 strncpy(code, string[i], stringLength);
107 code += stringLength;
108 }
109
110 mSource[totalLength] = '\0';
111}
112
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000113int Shader::getInfoLogLength() const
114{
115 if (!mInfoLog)
116 {
117 return 0;
118 }
119 else
120 {
121 return strlen(mInfoLog) + 1;
122 }
123}
124
125void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
126{
127 int index = 0;
128
129 if (mInfoLog)
130 {
131 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
132 {
133 infoLog[index] = mInfoLog[index];
134 index++;
135 }
136 }
137
138 if (bufSize)
139 {
140 infoLog[index] = '\0';
141 }
142
143 if (length)
144 {
145 *length = index;
146 }
147}
148
149int Shader::getSourceLength() const
150{
151 if (!mSource)
152 {
153 return 0;
154 }
155 else
156 {
157 return strlen(mSource) + 1;
158 }
159}
160
zmo@google.coma574f782011-10-03 21:45:23 +0000161int Shader::getTranslatedSourceLength() const
162{
163 if (!mHlsl)
164 {
165 return 0;
166 }
167 else
168 {
169 return strlen(mHlsl) + 1;
170 }
171}
172
173void Shader::getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000174{
175 int index = 0;
176
zmo@google.coma574f782011-10-03 21:45:23 +0000177 if (source)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000178 {
zmo@google.coma574f782011-10-03 21:45:23 +0000179 while (index < bufSize - 1 && index < (int)strlen(source))
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000180 {
zmo@google.coma574f782011-10-03 21:45:23 +0000181 buffer[index] = source[index];
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000182 index++;
183 }
184 }
185
186 if (bufSize)
187 {
zmo@google.coma574f782011-10-03 21:45:23 +0000188 buffer[index] = '\0';
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000189 }
190
191 if (length)
192 {
193 *length = index;
194 }
195}
196
zmo@google.coma574f782011-10-03 21:45:23 +0000197void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer)
198{
199 getSourceImpl(mSource, bufSize, length, buffer);
200}
201
202void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer)
203{
204 getSourceImpl(mHlsl, bufSize, length, buffer);
205}
206
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207bool Shader::isCompiled()
208{
209 return mHlsl != NULL;
210}
211
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000212const char *Shader::getHLSL()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000213{
214 return mHlsl;
215}
216
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000217void Shader::addRef()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000218{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000219 mRefCount++;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000220}
221
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000222void Shader::release()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000224 mRefCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000225
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000226 if (mRefCount == 0 && mDeleteStatus)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000227 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000228 mResourceManager->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000229 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000230}
231
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000232unsigned int Shader::getRefCount() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000234 return mRefCount;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000235}
236
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000237bool Shader::isFlaggedForDeletion() const
238{
239 return mDeleteStatus;
240}
241
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000242void Shader::flagForDeletion()
243{
244 mDeleteStatus = true;
245}
246
247void Shader::releaseCompiler()
248{
249 ShDestruct(mFragmentCompiler);
250 ShDestruct(mVertexCompiler);
251
252 mFragmentCompiler = NULL;
253 mVertexCompiler = NULL;
alokp@chromium.org90033b92010-05-24 15:02:43 +0000254
255 ShFinalize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000256}
257
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000258void Shader::parseVaryings()
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000259{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000260 if (mHlsl)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000261 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000262 const char *input = strstr(mHlsl, "// Varyings") + 12;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000263
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000264 while(true)
265 {
266 char varyingType[256];
267 char varyingName[256];
268
daniel@transgaming.com7ea933f2010-12-12 08:52:42 +0000269 int matches = sscanf(input, "static %255s %255s", varyingType, varyingName);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000270
271 if (matches != 2)
272 {
273 break;
274 }
275
276 char *array = strstr(varyingName, "[");
277 int size = 1;
278
279 if (array)
280 {
281 size = atoi(array + 1);
282 *array = '\0';
283 }
284
daniel@transgaming.comcde6a612012-02-17 18:01:10 +0000285 mVaryings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000286
287 input = strstr(input, ";") + 2;
288 }
289
290 mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
291 mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
daniel@transgaming.combe5a0862010-07-28 19:20:37 +0000292 mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL;
293 mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000294 }
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000295}
296
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000297void Shader::compileToHLSL(void *compiler)
298{
299 if (isCompiled() || !mSource)
300 {
301 return;
302 }
303
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000304 delete[] mInfoLog;
305 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000306
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000307 int compileOptions = SH_OBJECT_CODE;
308 std::string sourcePath;
309 if (perfActive())
310 {
311 sourcePath = getTempPath();
312 writeFile(sourcePath.c_str(), mSource, strlen(mSource));
313 compileOptions |= SH_LINE_DIRECTIVES;
314 }
315
316 int result;
317 if (sourcePath.empty())
318 {
319 result = ShCompile(compiler, &mSource, 1, compileOptions);
320 }
321 else
322 {
323 const char* sourceStrings[2] =
324 {
325 sourcePath.c_str(),
326 mSource
327 };
328
329 result = ShCompile(compiler, sourceStrings, 2, compileOptions | SH_SOURCE_PATH);
330 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000331
332 if (result)
333 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000334 int objCodeLen = 0;
335 ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen);
336 mHlsl = new char[objCodeLen];
337 ShGetObjectCode(compiler, mHlsl);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000338 }
339 else
340 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000341 int infoLogLen = 0;
342 ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
343 mInfoLog = new char[infoLogLen];
344 ShGetInfoLog(compiler, mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000346 TRACE("\n%s", mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000347 }
348}
349
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000350GLenum Shader::parseType(const std::string &type)
351{
352 if (type == "float")
353 {
354 return GL_FLOAT;
355 }
356 else if (type == "float2")
357 {
358 return GL_FLOAT_VEC2;
359 }
360 else if (type == "float3")
361 {
362 return GL_FLOAT_VEC3;
363 }
364 else if (type == "float4")
365 {
366 return GL_FLOAT_VEC4;
367 }
368 else if (type == "float2x2")
369 {
370 return GL_FLOAT_MAT2;
371 }
372 else if (type == "float3x3")
373 {
374 return GL_FLOAT_MAT3;
375 }
376 else if (type == "float4x4")
377 {
378 return GL_FLOAT_MAT4;
379 }
380 else UNREACHABLE();
381
382 return GL_NONE;
383}
384
385// true if varying x has a higher priority in packing than y
386bool Shader::compareVarying(const Varying &x, const Varying &y)
387{
388 if(x.type == y.type)
389 {
390 return x.size > y.size;
391 }
392
393 switch (x.type)
394 {
395 case GL_FLOAT_MAT4: return true;
396 case GL_FLOAT_MAT2:
397 switch(y.type)
398 {
399 case GL_FLOAT_MAT4: return false;
400 case GL_FLOAT_MAT2: return true;
401 case GL_FLOAT_VEC4: return true;
402 case GL_FLOAT_MAT3: return true;
403 case GL_FLOAT_VEC3: return true;
404 case GL_FLOAT_VEC2: return true;
405 case GL_FLOAT: return true;
406 default: UNREACHABLE();
407 }
408 break;
409 case GL_FLOAT_VEC4:
410 switch(y.type)
411 {
412 case GL_FLOAT_MAT4: return false;
413 case GL_FLOAT_MAT2: return false;
414 case GL_FLOAT_VEC4: return true;
415 case GL_FLOAT_MAT3: return true;
416 case GL_FLOAT_VEC3: return true;
417 case GL_FLOAT_VEC2: return true;
418 case GL_FLOAT: return true;
419 default: UNREACHABLE();
420 }
421 break;
422 case GL_FLOAT_MAT3:
423 switch(y.type)
424 {
425 case GL_FLOAT_MAT4: return false;
426 case GL_FLOAT_MAT2: return false;
427 case GL_FLOAT_VEC4: return false;
428 case GL_FLOAT_MAT3: return true;
429 case GL_FLOAT_VEC3: return true;
430 case GL_FLOAT_VEC2: return true;
431 case GL_FLOAT: return true;
432 default: UNREACHABLE();
433 }
434 break;
435 case GL_FLOAT_VEC3:
436 switch(y.type)
437 {
438 case GL_FLOAT_MAT4: return false;
439 case GL_FLOAT_MAT2: return false;
440 case GL_FLOAT_VEC4: return false;
441 case GL_FLOAT_MAT3: return false;
442 case GL_FLOAT_VEC3: return true;
443 case GL_FLOAT_VEC2: return true;
444 case GL_FLOAT: return true;
445 default: UNREACHABLE();
446 }
447 break;
448 case GL_FLOAT_VEC2:
449 switch(y.type)
450 {
451 case GL_FLOAT_MAT4: return false;
452 case GL_FLOAT_MAT2: return false;
453 case GL_FLOAT_VEC4: return false;
454 case GL_FLOAT_MAT3: return false;
455 case GL_FLOAT_VEC3: return false;
456 case GL_FLOAT_VEC2: return true;
457 case GL_FLOAT: return true;
458 default: UNREACHABLE();
459 }
460 break;
461 case GL_FLOAT: return false;
462 default: UNREACHABLE();
463 }
464
465 return false;
466}
467
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000468VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000469{
470}
471
472VertexShader::~VertexShader()
473{
474}
475
476GLenum VertexShader::getType()
477{
478 return GL_VERTEX_SHADER;
479}
480
481void VertexShader::compile()
482{
483 compileToHLSL(mVertexCompiler);
484 parseAttributes();
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000485 parseVaryings();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000486}
487
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000488int VertexShader::getSemanticIndex(const std::string &attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000489{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000490 if (!attributeName.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000491 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000492 int semanticIndex = 0;
493 for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000494 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000495 if (attribute->name == attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000496 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000497 return semanticIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000498 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000499
500 semanticIndex += VariableRowCount(attribute->type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000501 }
502 }
503
504 return -1;
505}
506
507void VertexShader::parseAttributes()
508{
daniel@transgaming.com2cdf8332012-02-17 18:00:50 +0000509 const char *hlsl = getHLSL();
510 if (hlsl)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000511 {
daniel@transgaming.com2cdf8332012-02-17 18:00:50 +0000512 const char *input = strstr(hlsl, "// Attributes") + 14;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000513
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000514 while(true)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000515 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000516 char attributeType[256];
517 char attributeName[256];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000518
daniel@transgaming.com7ea933f2010-12-12 08:52:42 +0000519 int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000520
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000521 if (matches != 2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000522 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000523 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000524 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000525
526 mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
527
528 input = strstr(input, ";") + 2;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000529 }
530 }
531}
532
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000533FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000534{
535}
536
537FragmentShader::~FragmentShader()
538{
539}
540
541GLenum FragmentShader::getType()
542{
543 return GL_FRAGMENT_SHADER;
544}
545
546void FragmentShader::compile()
547{
548 compileToHLSL(mFragmentCompiler);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000549 parseVaryings();
daniel@transgaming.comcde6a612012-02-17 18:01:10 +0000550 mVaryings.sort(compareVarying);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000551}
552}