blob: 6bcb2c7b1235158a39b9cf9dd1ac85bdea63b9fd [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);
alokp@chromium.org94a86ad2010-08-25 20:02:11 +000039 resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
40 resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
41 resources.MaxVaryingVectors = MAX_VARYING_VECTORS;
42 resources.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
43 resources.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
44 resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
45 resources.MaxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS;
46 resources.MaxDrawBuffers = MAX_DRAW_BUFFERS;
alokp@chromium.orgd303ef92010-09-09 17:30:15 +000047 resources.OES_standard_derivatives = 1;
alokp@chromium.orge4249f02010-07-26 18:13:52 +000048
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000049 mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, &resources);
50 mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, &resources);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000051 }
52 }
53
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000054 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000055 mDeleteStatus = false;
56}
57
58Shader::~Shader()
59{
60 delete[] mSource;
61 delete[] mHlsl;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000062 delete[] mInfoLog;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000063}
64
daniel@transgaming.com6c785212010-03-30 03:36:17 +000065GLuint Shader::getHandle() const
66{
67 return mHandle;
68}
69
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000070void Shader::setSource(GLsizei count, const char **string, const GLint *length)
71{
72 delete[] mSource;
73 int totalLength = 0;
74
75 for (int i = 0; i < count; i++)
76 {
77 if (length && length[i] >= 0)
78 {
79 totalLength += length[i];
80 }
81 else
82 {
83 totalLength += (int)strlen(string[i]);
84 }
85 }
86
87 mSource = new char[totalLength + 1];
88 char *code = mSource;
89
90 for (int i = 0; i < count; i++)
91 {
92 int stringLength;
93
94 if (length && length[i] >= 0)
95 {
96 stringLength = length[i];
97 }
98 else
99 {
100 stringLength = (int)strlen(string[i]);
101 }
102
103 strncpy(code, string[i], stringLength);
104 code += stringLength;
105 }
106
107 mSource[totalLength] = '\0';
108}
109
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000110int Shader::getInfoLogLength() const
111{
112 if (!mInfoLog)
113 {
114 return 0;
115 }
116 else
117 {
118 return strlen(mInfoLog) + 1;
119 }
120}
121
122void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
123{
124 int index = 0;
125
126 if (mInfoLog)
127 {
128 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
129 {
130 infoLog[index] = mInfoLog[index];
131 index++;
132 }
133 }
134
135 if (bufSize)
136 {
137 infoLog[index] = '\0';
138 }
139
140 if (length)
141 {
142 *length = index;
143 }
144}
145
146int Shader::getSourceLength() const
147{
148 if (!mSource)
149 {
150 return 0;
151 }
152 else
153 {
154 return strlen(mSource) + 1;
155 }
156}
157
158void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
159{
160 int index = 0;
161
162 if (mSource)
163 {
daniel@transgaming.com41187f12010-04-01 13:39:29 +0000164 while (index < bufSize - 1 && index < (int)strlen(mSource))
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000165 {
166 source[index] = mSource[index];
167 index++;
168 }
169 }
170
171 if (bufSize)
172 {
173 source[index] = '\0';
174 }
175
176 if (length)
177 {
178 *length = index;
179 }
180}
181
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182bool Shader::isCompiled()
183{
184 return mHlsl != NULL;
185}
186
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000187const char *Shader::getHLSL()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000188{
189 return mHlsl;
190}
191
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000192void Shader::addRef()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000193{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000194 mRefCount++;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000195}
196
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000197void Shader::release()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000198{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000199 mRefCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000200
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000201 if (mRefCount == 0 && mDeleteStatus)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000202 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000203 mResourceManager->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000204 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000205}
206
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000207unsigned int Shader::getRefCount() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000208{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000209 return mRefCount;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210}
211
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000212bool Shader::isFlaggedForDeletion() const
213{
214 return mDeleteStatus;
215}
216
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000217void Shader::flagForDeletion()
218{
219 mDeleteStatus = true;
220}
221
222void Shader::releaseCompiler()
223{
224 ShDestruct(mFragmentCompiler);
225 ShDestruct(mVertexCompiler);
226
227 mFragmentCompiler = NULL;
228 mVertexCompiler = NULL;
alokp@chromium.org90033b92010-05-24 15:02:43 +0000229
230 ShFinalize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000231}
232
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000233void Shader::parseVaryings()
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000234{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000235 if (mHlsl)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000236 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000237 const char *input = strstr(mHlsl, "// Varyings") + 12;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000238
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000239 while(true)
240 {
241 char varyingType[256];
242 char varyingName[256];
243
244 int matches = sscanf(input, "static %s %s", varyingType, varyingName);
245
246 if (matches != 2)
247 {
248 break;
249 }
250
251 char *array = strstr(varyingName, "[");
252 int size = 1;
253
254 if (array)
255 {
256 size = atoi(array + 1);
257 *array = '\0';
258 }
259
260 varyings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
261
262 input = strstr(input, ";") + 2;
263 }
264
265 mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
266 mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
daniel@transgaming.combe5a0862010-07-28 19:20:37 +0000267 mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL;
268 mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000269 }
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000270}
271
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000272void Shader::compileToHLSL(void *compiler)
273{
274 if (isCompiled() || !mSource)
275 {
276 return;
277 }
278
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000279 TRACE("\n%s", mSource);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000280
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000281 delete[] mInfoLog;
282 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000283
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000284 int result = ShCompile(compiler, &mSource, 1, SH_OBJECT_CODE);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000285
286 if (result)
287 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000288 int objCodeLen = 0;
289 ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen);
290 mHlsl = new char[objCodeLen];
291 ShGetObjectCode(compiler, mHlsl);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000292
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000293 TRACE("\n%s", mHlsl);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000294 }
295 else
296 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000297 int infoLogLen = 0;
298 ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
299 mInfoLog = new char[infoLogLen];
300 ShGetInfoLog(compiler, mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000301
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000302 TRACE("\n%s", mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000303 }
304}
305
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000306GLenum Shader::parseType(const std::string &type)
307{
308 if (type == "float")
309 {
310 return GL_FLOAT;
311 }
312 else if (type == "float2")
313 {
314 return GL_FLOAT_VEC2;
315 }
316 else if (type == "float3")
317 {
318 return GL_FLOAT_VEC3;
319 }
320 else if (type == "float4")
321 {
322 return GL_FLOAT_VEC4;
323 }
324 else if (type == "float2x2")
325 {
326 return GL_FLOAT_MAT2;
327 }
328 else if (type == "float3x3")
329 {
330 return GL_FLOAT_MAT3;
331 }
332 else if (type == "float4x4")
333 {
334 return GL_FLOAT_MAT4;
335 }
336 else UNREACHABLE();
337
338 return GL_NONE;
339}
340
341// true if varying x has a higher priority in packing than y
342bool Shader::compareVarying(const Varying &x, const Varying &y)
343{
344 if(x.type == y.type)
345 {
346 return x.size > y.size;
347 }
348
349 switch (x.type)
350 {
351 case GL_FLOAT_MAT4: return true;
352 case GL_FLOAT_MAT2:
353 switch(y.type)
354 {
355 case GL_FLOAT_MAT4: return false;
356 case GL_FLOAT_MAT2: return true;
357 case GL_FLOAT_VEC4: return true;
358 case GL_FLOAT_MAT3: return true;
359 case GL_FLOAT_VEC3: return true;
360 case GL_FLOAT_VEC2: return true;
361 case GL_FLOAT: return true;
362 default: UNREACHABLE();
363 }
364 break;
365 case GL_FLOAT_VEC4:
366 switch(y.type)
367 {
368 case GL_FLOAT_MAT4: return false;
369 case GL_FLOAT_MAT2: return false;
370 case GL_FLOAT_VEC4: return true;
371 case GL_FLOAT_MAT3: return true;
372 case GL_FLOAT_VEC3: return true;
373 case GL_FLOAT_VEC2: return true;
374 case GL_FLOAT: return true;
375 default: UNREACHABLE();
376 }
377 break;
378 case GL_FLOAT_MAT3:
379 switch(y.type)
380 {
381 case GL_FLOAT_MAT4: return false;
382 case GL_FLOAT_MAT2: return false;
383 case GL_FLOAT_VEC4: return false;
384 case GL_FLOAT_MAT3: return true;
385 case GL_FLOAT_VEC3: return true;
386 case GL_FLOAT_VEC2: return true;
387 case GL_FLOAT: return true;
388 default: UNREACHABLE();
389 }
390 break;
391 case GL_FLOAT_VEC3:
392 switch(y.type)
393 {
394 case GL_FLOAT_MAT4: return false;
395 case GL_FLOAT_MAT2: return false;
396 case GL_FLOAT_VEC4: return false;
397 case GL_FLOAT_MAT3: return false;
398 case GL_FLOAT_VEC3: return true;
399 case GL_FLOAT_VEC2: return true;
400 case GL_FLOAT: return true;
401 default: UNREACHABLE();
402 }
403 break;
404 case GL_FLOAT_VEC2:
405 switch(y.type)
406 {
407 case GL_FLOAT_MAT4: return false;
408 case GL_FLOAT_MAT2: return false;
409 case GL_FLOAT_VEC4: return false;
410 case GL_FLOAT_MAT3: return false;
411 case GL_FLOAT_VEC3: return false;
412 case GL_FLOAT_VEC2: return true;
413 case GL_FLOAT: return true;
414 default: UNREACHABLE();
415 }
416 break;
417 case GL_FLOAT: return false;
418 default: UNREACHABLE();
419 }
420
421 return false;
422}
423
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000424VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000425{
426}
427
428VertexShader::~VertexShader()
429{
430}
431
432GLenum VertexShader::getType()
433{
434 return GL_VERTEX_SHADER;
435}
436
437void VertexShader::compile()
438{
439 compileToHLSL(mVertexCompiler);
440 parseAttributes();
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000441 parseVaryings();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442}
443
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000444int VertexShader::getSemanticIndex(const std::string &attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000445{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000446 if (!attributeName.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000447 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000448 int semanticIndex = 0;
449 for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000450 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000451 if (attribute->name == attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000452 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000453 return semanticIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000454 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000455
456 semanticIndex += VariableRowCount(attribute->type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000457 }
458 }
459
460 return -1;
461}
462
463void VertexShader::parseAttributes()
464{
465 if (mHlsl)
466 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000467 const char *input = strstr(mHlsl, "// Attributes") + 14;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000468
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000469 while(true)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000470 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000471 char attributeType[256];
472 char attributeName[256];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000473
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000474 int matches = sscanf(input, "static %s _%s", attributeType, attributeName);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000475
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000476 if (matches != 2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000477 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000478 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000479 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000480
481 mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
482
483 input = strstr(input, ";") + 2;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000484 }
485 }
486}
487
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000488FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000489{
490}
491
492FragmentShader::~FragmentShader()
493{
494}
495
496GLenum FragmentShader::getType()
497{
498 return GL_FRAGMENT_SHADER;
499}
500
501void FragmentShader::compile()
502{
503 compileToHLSL(mFragmentCompiler);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000504 parseVaryings();
505 varyings.sort(compareVarying);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000506}
507}