blob: b73ef2af94cfa4d141fc163f9a92f927620c5ef1 [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.orge4249f02010-07-26 18:13:52 +000037 TBuiltInResource resources;
alokp@chromium.org94a86ad2010-08-25 20:02:11 +000038 ShInitBuiltInResource(&resources);
39 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.orge4249f02010-07-26 18:13:52 +000047
48 mFragmentCompiler = ShConstructCompiler(EShLangFragment, EShSpecGLES2, &resources);
49 mVertexCompiler = ShConstructCompiler(EShLangVertex, EShSpecGLES2, &resources);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000050 }
51 }
52
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000053 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000054 mDeleteStatus = false;
55}
56
57Shader::~Shader()
58{
59 delete[] mSource;
60 delete[] mHlsl;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000061 delete[] mInfoLog;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000062}
63
daniel@transgaming.com6c785212010-03-30 03:36:17 +000064GLuint Shader::getHandle() const
65{
66 return mHandle;
67}
68
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000069void Shader::setSource(GLsizei count, const char **string, const GLint *length)
70{
71 delete[] mSource;
72 int totalLength = 0;
73
74 for (int i = 0; i < count; i++)
75 {
76 if (length && length[i] >= 0)
77 {
78 totalLength += length[i];
79 }
80 else
81 {
82 totalLength += (int)strlen(string[i]);
83 }
84 }
85
86 mSource = new char[totalLength + 1];
87 char *code = mSource;
88
89 for (int i = 0; i < count; i++)
90 {
91 int stringLength;
92
93 if (length && length[i] >= 0)
94 {
95 stringLength = length[i];
96 }
97 else
98 {
99 stringLength = (int)strlen(string[i]);
100 }
101
102 strncpy(code, string[i], stringLength);
103 code += stringLength;
104 }
105
106 mSource[totalLength] = '\0';
107}
108
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000109int Shader::getInfoLogLength() const
110{
111 if (!mInfoLog)
112 {
113 return 0;
114 }
115 else
116 {
117 return strlen(mInfoLog) + 1;
118 }
119}
120
121void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
122{
123 int index = 0;
124
125 if (mInfoLog)
126 {
127 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
128 {
129 infoLog[index] = mInfoLog[index];
130 index++;
131 }
132 }
133
134 if (bufSize)
135 {
136 infoLog[index] = '\0';
137 }
138
139 if (length)
140 {
141 *length = index;
142 }
143}
144
145int Shader::getSourceLength() const
146{
147 if (!mSource)
148 {
149 return 0;
150 }
151 else
152 {
153 return strlen(mSource) + 1;
154 }
155}
156
157void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
158{
159 int index = 0;
160
161 if (mSource)
162 {
daniel@transgaming.com41187f12010-04-01 13:39:29 +0000163 while (index < bufSize - 1 && index < (int)strlen(mSource))
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000164 {
165 source[index] = mSource[index];
166 index++;
167 }
168 }
169
170 if (bufSize)
171 {
172 source[index] = '\0';
173 }
174
175 if (length)
176 {
177 *length = index;
178 }
179}
180
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000181bool Shader::isCompiled()
182{
183 return mHlsl != NULL;
184}
185
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000186const char *Shader::getHLSL()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000187{
188 return mHlsl;
189}
190
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000191void Shader::addRef()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000192{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000193 mRefCount++;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000194}
195
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000196void Shader::release()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000197{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000198 mRefCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000199
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000200 if (mRefCount == 0 && mDeleteStatus)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000201 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000202 mResourceManager->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000203 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000204}
205
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000206unsigned int Shader::getRefCount() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000208 return mRefCount;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000209}
210
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000211bool Shader::isFlaggedForDeletion() const
212{
213 return mDeleteStatus;
214}
215
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000216void Shader::flagForDeletion()
217{
218 mDeleteStatus = true;
219}
220
221void Shader::releaseCompiler()
222{
223 ShDestruct(mFragmentCompiler);
224 ShDestruct(mVertexCompiler);
225
226 mFragmentCompiler = NULL;
227 mVertexCompiler = NULL;
alokp@chromium.org90033b92010-05-24 15:02:43 +0000228
229 ShFinalize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000230}
231
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000232void Shader::parseVaryings()
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000233{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000234 if (mHlsl)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000235 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000236 const char *input = strstr(mHlsl, "// Varyings") + 12;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000237
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000238 while(true)
239 {
240 char varyingType[256];
241 char varyingName[256];
242
243 int matches = sscanf(input, "static %s %s", varyingType, varyingName);
244
245 if (matches != 2)
246 {
247 break;
248 }
249
250 char *array = strstr(varyingName, "[");
251 int size = 1;
252
253 if (array)
254 {
255 size = atoi(array + 1);
256 *array = '\0';
257 }
258
259 varyings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
260
261 input = strstr(input, ";") + 2;
262 }
263
264 mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
265 mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
daniel@transgaming.combe5a0862010-07-28 19:20:37 +0000266 mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL;
267 mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000268 }
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000269}
270
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000271void Shader::compileToHLSL(void *compiler)
272{
273 if (isCompiled() || !mSource)
274 {
275 return;
276 }
277
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000278 TRACE("\n%s", mSource);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000280 delete[] mInfoLog;
281 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000282
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000283 int result = ShCompile(compiler, &mSource, 1, EShOptNone, EDebugOpNone);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000284 const char *obj = ShGetObjectCode(compiler);
285 const char *info = ShGetInfoLog(compiler);
286
287 if (result)
288 {
289 mHlsl = new char[strlen(obj) + 1];
290 strcpy(mHlsl, obj);
291
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000292 TRACE("\n%s", mHlsl);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000293 }
294 else
295 {
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000296 mInfoLog = new char[strlen(info) + 1];
297 strcpy(mInfoLog, info);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000298
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000299 TRACE("\n%s", mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000300 }
301}
302
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000303GLenum Shader::parseType(const std::string &type)
304{
305 if (type == "float")
306 {
307 return GL_FLOAT;
308 }
309 else if (type == "float2")
310 {
311 return GL_FLOAT_VEC2;
312 }
313 else if (type == "float3")
314 {
315 return GL_FLOAT_VEC3;
316 }
317 else if (type == "float4")
318 {
319 return GL_FLOAT_VEC4;
320 }
321 else if (type == "float2x2")
322 {
323 return GL_FLOAT_MAT2;
324 }
325 else if (type == "float3x3")
326 {
327 return GL_FLOAT_MAT3;
328 }
329 else if (type == "float4x4")
330 {
331 return GL_FLOAT_MAT4;
332 }
333 else UNREACHABLE();
334
335 return GL_NONE;
336}
337
338// true if varying x has a higher priority in packing than y
339bool Shader::compareVarying(const Varying &x, const Varying &y)
340{
341 if(x.type == y.type)
342 {
343 return x.size > y.size;
344 }
345
346 switch (x.type)
347 {
348 case GL_FLOAT_MAT4: return true;
349 case GL_FLOAT_MAT2:
350 switch(y.type)
351 {
352 case GL_FLOAT_MAT4: return false;
353 case GL_FLOAT_MAT2: return true;
354 case GL_FLOAT_VEC4: return true;
355 case GL_FLOAT_MAT3: return true;
356 case GL_FLOAT_VEC3: return true;
357 case GL_FLOAT_VEC2: return true;
358 case GL_FLOAT: return true;
359 default: UNREACHABLE();
360 }
361 break;
362 case GL_FLOAT_VEC4:
363 switch(y.type)
364 {
365 case GL_FLOAT_MAT4: return false;
366 case GL_FLOAT_MAT2: return false;
367 case GL_FLOAT_VEC4: return true;
368 case GL_FLOAT_MAT3: return true;
369 case GL_FLOAT_VEC3: return true;
370 case GL_FLOAT_VEC2: return true;
371 case GL_FLOAT: return true;
372 default: UNREACHABLE();
373 }
374 break;
375 case GL_FLOAT_MAT3:
376 switch(y.type)
377 {
378 case GL_FLOAT_MAT4: return false;
379 case GL_FLOAT_MAT2: return false;
380 case GL_FLOAT_VEC4: return false;
381 case GL_FLOAT_MAT3: return true;
382 case GL_FLOAT_VEC3: return true;
383 case GL_FLOAT_VEC2: return true;
384 case GL_FLOAT: return true;
385 default: UNREACHABLE();
386 }
387 break;
388 case GL_FLOAT_VEC3:
389 switch(y.type)
390 {
391 case GL_FLOAT_MAT4: return false;
392 case GL_FLOAT_MAT2: return false;
393 case GL_FLOAT_VEC4: return false;
394 case GL_FLOAT_MAT3: return false;
395 case GL_FLOAT_VEC3: return true;
396 case GL_FLOAT_VEC2: return true;
397 case GL_FLOAT: return true;
398 default: UNREACHABLE();
399 }
400 break;
401 case GL_FLOAT_VEC2:
402 switch(y.type)
403 {
404 case GL_FLOAT_MAT4: return false;
405 case GL_FLOAT_MAT2: return false;
406 case GL_FLOAT_VEC4: return false;
407 case GL_FLOAT_MAT3: return false;
408 case GL_FLOAT_VEC3: return false;
409 case GL_FLOAT_VEC2: return true;
410 case GL_FLOAT: return true;
411 default: UNREACHABLE();
412 }
413 break;
414 case GL_FLOAT: return false;
415 default: UNREACHABLE();
416 }
417
418 return false;
419}
420
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000421VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000422{
423}
424
425VertexShader::~VertexShader()
426{
427}
428
429GLenum VertexShader::getType()
430{
431 return GL_VERTEX_SHADER;
432}
433
434void VertexShader::compile()
435{
436 compileToHLSL(mVertexCompiler);
437 parseAttributes();
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000438 parseVaryings();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000439}
440
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000441int VertexShader::getSemanticIndex(const std::string &attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000443 if (!attributeName.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000444 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000445 int semanticIndex = 0;
446 for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000447 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000448 if (attribute->name == attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000449 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000450 return semanticIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000451 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000452
453 semanticIndex += VariableRowCount(attribute->type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000454 }
455 }
456
457 return -1;
458}
459
460void VertexShader::parseAttributes()
461{
462 if (mHlsl)
463 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000464 const char *input = strstr(mHlsl, "// Attributes") + 14;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000465
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000466 while(true)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000467 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000468 char attributeType[256];
469 char attributeName[256];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000470
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000471 int matches = sscanf(input, "static %s _%s", attributeType, attributeName);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000472
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000473 if (matches != 2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000474 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000475 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000476 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000477
478 mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
479
480 input = strstr(input, ";") + 2;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000481 }
482 }
483}
484
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000485FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000486{
487}
488
489FragmentShader::~FragmentShader()
490{
491}
492
493GLenum FragmentShader::getType()
494{
495 return GL_FRAGMENT_SHADER;
496}
497
498void FragmentShader::compile()
499{
500 compileToHLSL(mFragmentCompiler);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000501 parseVaryings();
502 varyings.sort(compareVarying);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000503}
504}