blob: 4c969d67640df5887cd5bda6d704c1aff48b2a4c [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);
daniel@transgaming.com396c6432010-11-26 16:26:12 +000039 Context *context = getContext();
40
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();
alokp@chromium.org94a86ad2010-08-25 20:02:11 +000044 resources.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
45 resources.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
46 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
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000051 mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, &resources);
52 mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, &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
160void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
161{
162 int index = 0;
163
164 if (mSource)
165 {
daniel@transgaming.com41187f12010-04-01 13:39:29 +0000166 while (index < bufSize - 1 && index < (int)strlen(mSource))
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000167 {
168 source[index] = mSource[index];
169 index++;
170 }
171 }
172
173 if (bufSize)
174 {
175 source[index] = '\0';
176 }
177
178 if (length)
179 {
180 *length = index;
181 }
182}
183
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184bool Shader::isCompiled()
185{
186 return mHlsl != NULL;
187}
188
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000189const char *Shader::getHLSL()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000190{
191 return mHlsl;
192}
193
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000194void Shader::addRef()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000195{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000196 mRefCount++;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000197}
198
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000199void Shader::release()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000200{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000201 mRefCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000202
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000203 if (mRefCount == 0 && mDeleteStatus)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000204 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000205 mResourceManager->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000206 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207}
208
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000209unsigned int Shader::getRefCount() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000211 return mRefCount;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000212}
213
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000214bool Shader::isFlaggedForDeletion() const
215{
216 return mDeleteStatus;
217}
218
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000219void Shader::flagForDeletion()
220{
221 mDeleteStatus = true;
222}
223
224void Shader::releaseCompiler()
225{
226 ShDestruct(mFragmentCompiler);
227 ShDestruct(mVertexCompiler);
228
229 mFragmentCompiler = NULL;
230 mVertexCompiler = NULL;
alokp@chromium.org90033b92010-05-24 15:02:43 +0000231
232 ShFinalize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233}
234
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000235void Shader::parseVaryings()
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000236{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000237 if (mHlsl)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000238 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000239 const char *input = strstr(mHlsl, "// Varyings") + 12;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000240
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000241 while(true)
242 {
243 char varyingType[256];
244 char varyingName[256];
245
daniel@transgaming.com7ea933f2010-12-12 08:52:42 +0000246 int matches = sscanf(input, "static %255s %255s", varyingType, varyingName);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000247
248 if (matches != 2)
249 {
250 break;
251 }
252
253 char *array = strstr(varyingName, "[");
254 int size = 1;
255
256 if (array)
257 {
258 size = atoi(array + 1);
259 *array = '\0';
260 }
261
262 varyings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
263
264 input = strstr(input, ";") + 2;
265 }
266
267 mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
268 mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
daniel@transgaming.combe5a0862010-07-28 19:20:37 +0000269 mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL;
270 mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000271 }
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000272}
273
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000274void Shader::compileToHLSL(void *compiler)
275{
276 if (isCompiled() || !mSource)
277 {
278 return;
279 }
280
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000281 TRACE("\n%s", mSource);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000282
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000283 delete[] mInfoLog;
284 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000285
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000286 int result = ShCompile(compiler, &mSource, 1, SH_OBJECT_CODE);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000287
288 if (result)
289 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000290 int objCodeLen = 0;
291 ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen);
292 mHlsl = new char[objCodeLen];
293 ShGetObjectCode(compiler, mHlsl);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000294
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000295 TRACE("\n%s", mHlsl);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296 }
297 else
298 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000299 int infoLogLen = 0;
300 ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
301 mInfoLog = new char[infoLogLen];
302 ShGetInfoLog(compiler, mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000303
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000304 TRACE("\n%s", mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000305 }
306}
307
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000308GLenum Shader::parseType(const std::string &type)
309{
310 if (type == "float")
311 {
312 return GL_FLOAT;
313 }
314 else if (type == "float2")
315 {
316 return GL_FLOAT_VEC2;
317 }
318 else if (type == "float3")
319 {
320 return GL_FLOAT_VEC3;
321 }
322 else if (type == "float4")
323 {
324 return GL_FLOAT_VEC4;
325 }
326 else if (type == "float2x2")
327 {
328 return GL_FLOAT_MAT2;
329 }
330 else if (type == "float3x3")
331 {
332 return GL_FLOAT_MAT3;
333 }
334 else if (type == "float4x4")
335 {
336 return GL_FLOAT_MAT4;
337 }
338 else UNREACHABLE();
339
340 return GL_NONE;
341}
342
343// true if varying x has a higher priority in packing than y
344bool Shader::compareVarying(const Varying &x, const Varying &y)
345{
346 if(x.type == y.type)
347 {
348 return x.size > y.size;
349 }
350
351 switch (x.type)
352 {
353 case GL_FLOAT_MAT4: return true;
354 case GL_FLOAT_MAT2:
355 switch(y.type)
356 {
357 case GL_FLOAT_MAT4: return false;
358 case GL_FLOAT_MAT2: return true;
359 case GL_FLOAT_VEC4: return true;
360 case GL_FLOAT_MAT3: return true;
361 case GL_FLOAT_VEC3: return true;
362 case GL_FLOAT_VEC2: return true;
363 case GL_FLOAT: return true;
364 default: UNREACHABLE();
365 }
366 break;
367 case GL_FLOAT_VEC4:
368 switch(y.type)
369 {
370 case GL_FLOAT_MAT4: return false;
371 case GL_FLOAT_MAT2: return false;
372 case GL_FLOAT_VEC4: return true;
373 case GL_FLOAT_MAT3: return true;
374 case GL_FLOAT_VEC3: return true;
375 case GL_FLOAT_VEC2: return true;
376 case GL_FLOAT: return true;
377 default: UNREACHABLE();
378 }
379 break;
380 case GL_FLOAT_MAT3:
381 switch(y.type)
382 {
383 case GL_FLOAT_MAT4: return false;
384 case GL_FLOAT_MAT2: return false;
385 case GL_FLOAT_VEC4: return false;
386 case GL_FLOAT_MAT3: return true;
387 case GL_FLOAT_VEC3: return true;
388 case GL_FLOAT_VEC2: return true;
389 case GL_FLOAT: return true;
390 default: UNREACHABLE();
391 }
392 break;
393 case GL_FLOAT_VEC3:
394 switch(y.type)
395 {
396 case GL_FLOAT_MAT4: return false;
397 case GL_FLOAT_MAT2: return false;
398 case GL_FLOAT_VEC4: return false;
399 case GL_FLOAT_MAT3: return false;
400 case GL_FLOAT_VEC3: return true;
401 case GL_FLOAT_VEC2: return true;
402 case GL_FLOAT: return true;
403 default: UNREACHABLE();
404 }
405 break;
406 case GL_FLOAT_VEC2:
407 switch(y.type)
408 {
409 case GL_FLOAT_MAT4: return false;
410 case GL_FLOAT_MAT2: return false;
411 case GL_FLOAT_VEC4: return false;
412 case GL_FLOAT_MAT3: return false;
413 case GL_FLOAT_VEC3: return false;
414 case GL_FLOAT_VEC2: return true;
415 case GL_FLOAT: return true;
416 default: UNREACHABLE();
417 }
418 break;
419 case GL_FLOAT: return false;
420 default: UNREACHABLE();
421 }
422
423 return false;
424}
425
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000426VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000427{
428}
429
430VertexShader::~VertexShader()
431{
432}
433
434GLenum VertexShader::getType()
435{
436 return GL_VERTEX_SHADER;
437}
438
439void VertexShader::compile()
440{
441 compileToHLSL(mVertexCompiler);
442 parseAttributes();
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000443 parseVaryings();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000444}
445
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000446int VertexShader::getSemanticIndex(const std::string &attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000447{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000448 if (!attributeName.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000449 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000450 int semanticIndex = 0;
451 for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000452 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000453 if (attribute->name == attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000454 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000455 return semanticIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000456 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000457
458 semanticIndex += VariableRowCount(attribute->type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000459 }
460 }
461
462 return -1;
463}
464
465void VertexShader::parseAttributes()
466{
467 if (mHlsl)
468 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000469 const char *input = strstr(mHlsl, "// Attributes") + 14;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000470
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000471 while(true)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000472 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000473 char attributeType[256];
474 char attributeName[256];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000475
daniel@transgaming.com7ea933f2010-12-12 08:52:42 +0000476 int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000477
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000478 if (matches != 2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000479 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000480 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000481 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000482
483 mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
484
485 input = strstr(input, ";") + 2;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000486 }
487 }
488}
489
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000490FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000491{
492}
493
494FragmentShader::~FragmentShader()
495{
496}
497
498GLenum FragmentShader::getType()
499{
500 return GL_FRAGMENT_SHADER;
501}
502
503void FragmentShader::compile()
504{
505 compileToHLSL(mFragmentCompiler);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000506 parseVaryings();
507 varyings.sort(compareVarying);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000508}
509}