blob: 58eed078406543ceb121dc728213253be5ae0b3c [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 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// 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;
alokp@chromium.orge4249f02010-07-26 18:13:52 +000050
zmo@google.com5601ea02011-06-10 18:23:25 +000051 mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources);
52 mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000053 }
54 }
55
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000056 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000057 mDeleteStatus = false;
58}
59
60Shader::~Shader()
61{
62 delete[] mSource;
63 delete[] mHlsl;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000064 delete[] mInfoLog;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000065}
66
daniel@transgaming.com6c785212010-03-30 03:36:17 +000067GLuint Shader::getHandle() const
68{
69 return mHandle;
70}
71
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000072void Shader::setSource(GLsizei count, const char **string, const GLint *length)
73{
74 delete[] mSource;
75 int totalLength = 0;
76
77 for (int i = 0; i < count; i++)
78 {
79 if (length && length[i] >= 0)
80 {
81 totalLength += length[i];
82 }
83 else
84 {
85 totalLength += (int)strlen(string[i]);
86 }
87 }
88
89 mSource = new char[totalLength + 1];
90 char *code = mSource;
91
92 for (int i = 0; i < count; i++)
93 {
94 int stringLength;
95
96 if (length && length[i] >= 0)
97 {
98 stringLength = length[i];
99 }
100 else
101 {
102 stringLength = (int)strlen(string[i]);
103 }
104
105 strncpy(code, string[i], stringLength);
106 code += stringLength;
107 }
108
109 mSource[totalLength] = '\0';
110}
111
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000112int Shader::getInfoLogLength() const
113{
114 if (!mInfoLog)
115 {
116 return 0;
117 }
118 else
119 {
120 return strlen(mInfoLog) + 1;
121 }
122}
123
124void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
125{
126 int index = 0;
127
128 if (mInfoLog)
129 {
130 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
131 {
132 infoLog[index] = mInfoLog[index];
133 index++;
134 }
135 }
136
137 if (bufSize)
138 {
139 infoLog[index] = '\0';
140 }
141
142 if (length)
143 {
144 *length = index;
145 }
146}
147
148int Shader::getSourceLength() const
149{
150 if (!mSource)
151 {
152 return 0;
153 }
154 else
155 {
156 return strlen(mSource) + 1;
157 }
158}
159
zmo@google.coma574f782011-10-03 21:45:23 +0000160int Shader::getTranslatedSourceLength() const
161{
162 if (!mHlsl)
163 {
164 return 0;
165 }
166 else
167 {
168 return strlen(mHlsl) + 1;
169 }
170}
171
172void Shader::getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000173{
174 int index = 0;
175
zmo@google.coma574f782011-10-03 21:45:23 +0000176 if (source)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000177 {
zmo@google.coma574f782011-10-03 21:45:23 +0000178 while (index < bufSize - 1 && index < (int)strlen(source))
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000179 {
zmo@google.coma574f782011-10-03 21:45:23 +0000180 buffer[index] = source[index];
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000181 index++;
182 }
183 }
184
185 if (bufSize)
186 {
zmo@google.coma574f782011-10-03 21:45:23 +0000187 buffer[index] = '\0';
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000188 }
189
190 if (length)
191 {
192 *length = index;
193 }
194}
195
zmo@google.coma574f782011-10-03 21:45:23 +0000196void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer)
197{
198 getSourceImpl(mSource, bufSize, length, buffer);
199}
200
201void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer)
202{
203 getSourceImpl(mHlsl, bufSize, length, buffer);
204}
205
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000206bool Shader::isCompiled()
207{
208 return mHlsl != NULL;
209}
210
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000211const char *Shader::getHLSL()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000212{
213 return mHlsl;
214}
215
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000216void Shader::addRef()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000217{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000218 mRefCount++;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000219}
220
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000221void Shader::release()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000222{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000223 mRefCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000224
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000225 if (mRefCount == 0 && mDeleteStatus)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000226 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000227 mResourceManager->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000228 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000229}
230
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000231unsigned int Shader::getRefCount() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000232{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000233 return mRefCount;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000234}
235
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000236bool Shader::isFlaggedForDeletion() const
237{
238 return mDeleteStatus;
239}
240
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000241void Shader::flagForDeletion()
242{
243 mDeleteStatus = true;
244}
245
246void Shader::releaseCompiler()
247{
248 ShDestruct(mFragmentCompiler);
249 ShDestruct(mVertexCompiler);
250
251 mFragmentCompiler = NULL;
252 mVertexCompiler = NULL;
alokp@chromium.org90033b92010-05-24 15:02:43 +0000253
254 ShFinalize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000255}
256
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000257void Shader::parseVaryings()
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000258{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000259 if (mHlsl)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000260 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000261 const char *input = strstr(mHlsl, "// Varyings") + 12;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000262
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000263 while(true)
264 {
265 char varyingType[256];
266 char varyingName[256];
267
daniel@transgaming.com7ea933f2010-12-12 08:52:42 +0000268 int matches = sscanf(input, "static %255s %255s", varyingType, varyingName);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000269
270 if (matches != 2)
271 {
272 break;
273 }
274
275 char *array = strstr(varyingName, "[");
276 int size = 1;
277
278 if (array)
279 {
280 size = atoi(array + 1);
281 *array = '\0';
282 }
283
284 varyings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
285
286 input = strstr(input, ";") + 2;
287 }
288
289 mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
290 mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
daniel@transgaming.combe5a0862010-07-28 19:20:37 +0000291 mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL;
292 mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000293 }
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000294}
295
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296void Shader::compileToHLSL(void *compiler)
297{
298 if (isCompiled() || !mSource)
299 {
300 return;
301 }
302
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000303 delete[] mInfoLog;
304 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000305
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000306 int compileOptions = SH_OBJECT_CODE;
307 std::string sourcePath;
308 if (perfActive())
309 {
310 sourcePath = getTempPath();
311 writeFile(sourcePath.c_str(), mSource, strlen(mSource));
312 compileOptions |= SH_LINE_DIRECTIVES;
313 }
314
315 int result;
316 if (sourcePath.empty())
317 {
318 result = ShCompile(compiler, &mSource, 1, compileOptions);
319 }
320 else
321 {
322 const char* sourceStrings[2] =
323 {
324 sourcePath.c_str(),
325 mSource
326 };
327
328 result = ShCompile(compiler, sourceStrings, 2, compileOptions | SH_SOURCE_PATH);
329 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330
331 if (result)
332 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000333 int objCodeLen = 0;
334 ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen);
335 mHlsl = new char[objCodeLen];
336 ShGetObjectCode(compiler, mHlsl);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000337 }
338 else
339 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000340 int infoLogLen = 0;
341 ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
342 mInfoLog = new char[infoLogLen];
343 ShGetInfoLog(compiler, mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000344
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000345 TRACE("\n%s", mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000346 }
347}
348
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000349GLenum Shader::parseType(const std::string &type)
350{
351 if (type == "float")
352 {
353 return GL_FLOAT;
354 }
355 else if (type == "float2")
356 {
357 return GL_FLOAT_VEC2;
358 }
359 else if (type == "float3")
360 {
361 return GL_FLOAT_VEC3;
362 }
363 else if (type == "float4")
364 {
365 return GL_FLOAT_VEC4;
366 }
367 else if (type == "float2x2")
368 {
369 return GL_FLOAT_MAT2;
370 }
371 else if (type == "float3x3")
372 {
373 return GL_FLOAT_MAT3;
374 }
375 else if (type == "float4x4")
376 {
377 return GL_FLOAT_MAT4;
378 }
379 else UNREACHABLE();
380
381 return GL_NONE;
382}
383
384// true if varying x has a higher priority in packing than y
385bool Shader::compareVarying(const Varying &x, const Varying &y)
386{
387 if(x.type == y.type)
388 {
389 return x.size > y.size;
390 }
391
392 switch (x.type)
393 {
394 case GL_FLOAT_MAT4: return true;
395 case GL_FLOAT_MAT2:
396 switch(y.type)
397 {
398 case GL_FLOAT_MAT4: return false;
399 case GL_FLOAT_MAT2: return true;
400 case GL_FLOAT_VEC4: return true;
401 case GL_FLOAT_MAT3: return true;
402 case GL_FLOAT_VEC3: return true;
403 case GL_FLOAT_VEC2: return true;
404 case GL_FLOAT: return true;
405 default: UNREACHABLE();
406 }
407 break;
408 case GL_FLOAT_VEC4:
409 switch(y.type)
410 {
411 case GL_FLOAT_MAT4: return false;
412 case GL_FLOAT_MAT2: return false;
413 case GL_FLOAT_VEC4: return true;
414 case GL_FLOAT_MAT3: return true;
415 case GL_FLOAT_VEC3: return true;
416 case GL_FLOAT_VEC2: return true;
417 case GL_FLOAT: return true;
418 default: UNREACHABLE();
419 }
420 break;
421 case GL_FLOAT_MAT3:
422 switch(y.type)
423 {
424 case GL_FLOAT_MAT4: return false;
425 case GL_FLOAT_MAT2: return false;
426 case GL_FLOAT_VEC4: return false;
427 case GL_FLOAT_MAT3: return true;
428 case GL_FLOAT_VEC3: return true;
429 case GL_FLOAT_VEC2: return true;
430 case GL_FLOAT: return true;
431 default: UNREACHABLE();
432 }
433 break;
434 case GL_FLOAT_VEC3:
435 switch(y.type)
436 {
437 case GL_FLOAT_MAT4: return false;
438 case GL_FLOAT_MAT2: return false;
439 case GL_FLOAT_VEC4: return false;
440 case GL_FLOAT_MAT3: return false;
441 case GL_FLOAT_VEC3: return true;
442 case GL_FLOAT_VEC2: return true;
443 case GL_FLOAT: return true;
444 default: UNREACHABLE();
445 }
446 break;
447 case GL_FLOAT_VEC2:
448 switch(y.type)
449 {
450 case GL_FLOAT_MAT4: return false;
451 case GL_FLOAT_MAT2: return false;
452 case GL_FLOAT_VEC4: return false;
453 case GL_FLOAT_MAT3: return false;
454 case GL_FLOAT_VEC3: return false;
455 case GL_FLOAT_VEC2: return true;
456 case GL_FLOAT: return true;
457 default: UNREACHABLE();
458 }
459 break;
460 case GL_FLOAT: return false;
461 default: UNREACHABLE();
462 }
463
464 return false;
465}
466
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000467VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000468{
469}
470
471VertexShader::~VertexShader()
472{
473}
474
475GLenum VertexShader::getType()
476{
477 return GL_VERTEX_SHADER;
478}
479
480void VertexShader::compile()
481{
482 compileToHLSL(mVertexCompiler);
483 parseAttributes();
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000484 parseVaryings();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000485}
486
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000487int VertexShader::getSemanticIndex(const std::string &attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000488{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000489 if (!attributeName.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000490 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000491 int semanticIndex = 0;
492 for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000493 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000494 if (attribute->name == attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000495 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000496 return semanticIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000497 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000498
499 semanticIndex += VariableRowCount(attribute->type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000500 }
501 }
502
503 return -1;
504}
505
506void VertexShader::parseAttributes()
507{
508 if (mHlsl)
509 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000510 const char *input = strstr(mHlsl, "// Attributes") + 14;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000511
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000512 while(true)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000513 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000514 char attributeType[256];
515 char attributeName[256];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000516
daniel@transgaming.com7ea933f2010-12-12 08:52:42 +0000517 int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000518
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000519 if (matches != 2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000520 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000521 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000522 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000523
524 mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
525
526 input = strstr(input, ";") + 2;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000527 }
528 }
529}
530
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000531FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000532{
533}
534
535FragmentShader::~FragmentShader()
536{
537}
538
539GLenum FragmentShader::getType()
540{
541 return GL_FRAGMENT_SHADER;
542}
543
544void FragmentShader::compile()
545{
546 compileToHLSL(mFragmentCompiler);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000547 parseVaryings();
548 varyings.sort(compareVarying);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000549}
550}