blob: 730c1b52aca9167932a83b70d0e5c1d549ec79f9 [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.com95124342010-04-29 03:38:58 +000024Shader::Shader(Context *context, GLuint handle) : mHandle(handle), mContext(context)
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;
38 resources.maxVertexAttribs = MAX_VERTEX_ATTRIBS;
39 resources.maxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
40 resources.maxVaryingVectors = MAX_VARYING_VECTORS;
41 resources.maxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
42 resources.maxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
43 resources.maxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
44 resources.maxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS;
45 resources.maxDrawBuffers = MAX_DRAW_BUFFERS;
46
47 mFragmentCompiler = ShConstructCompiler(EShLangFragment, EShSpecGLES2, &resources);
48 mVertexCompiler = ShConstructCompiler(EShLangVertex, EShSpecGLES2, &resources);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000049 }
50 }
51
52 mAttachCount = 0;
53 mDeleteStatus = false;
54}
55
56Shader::~Shader()
57{
58 delete[] mSource;
59 delete[] mHlsl;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000060 delete[] mInfoLog;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000061}
62
daniel@transgaming.com6c785212010-03-30 03:36:17 +000063GLuint Shader::getHandle() const
64{
65 return mHandle;
66}
67
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000068void Shader::setSource(GLsizei count, const char **string, const GLint *length)
69{
70 delete[] mSource;
71 int totalLength = 0;
72
73 for (int i = 0; i < count; i++)
74 {
75 if (length && length[i] >= 0)
76 {
77 totalLength += length[i];
78 }
79 else
80 {
81 totalLength += (int)strlen(string[i]);
82 }
83 }
84
85 mSource = new char[totalLength + 1];
86 char *code = mSource;
87
88 for (int i = 0; i < count; i++)
89 {
90 int stringLength;
91
92 if (length && length[i] >= 0)
93 {
94 stringLength = length[i];
95 }
96 else
97 {
98 stringLength = (int)strlen(string[i]);
99 }
100
101 strncpy(code, string[i], stringLength);
102 code += stringLength;
103 }
104
105 mSource[totalLength] = '\0';
106}
107
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000108int Shader::getInfoLogLength() const
109{
110 if (!mInfoLog)
111 {
112 return 0;
113 }
114 else
115 {
116 return strlen(mInfoLog) + 1;
117 }
118}
119
120void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
121{
122 int index = 0;
123
124 if (mInfoLog)
125 {
126 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
127 {
128 infoLog[index] = mInfoLog[index];
129 index++;
130 }
131 }
132
133 if (bufSize)
134 {
135 infoLog[index] = '\0';
136 }
137
138 if (length)
139 {
140 *length = index;
141 }
142}
143
144int Shader::getSourceLength() const
145{
146 if (!mSource)
147 {
148 return 0;
149 }
150 else
151 {
152 return strlen(mSource) + 1;
153 }
154}
155
156void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
157{
158 int index = 0;
159
160 if (mSource)
161 {
daniel@transgaming.com41187f12010-04-01 13:39:29 +0000162 while (index < bufSize - 1 && index < (int)strlen(mSource))
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000163 {
164 source[index] = mSource[index];
165 index++;
166 }
167 }
168
169 if (bufSize)
170 {
171 source[index] = '\0';
172 }
173
174 if (length)
175 {
176 *length = index;
177 }
178}
179
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000180bool Shader::isCompiled()
181{
182 return mHlsl != NULL;
183}
184
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000185const char *Shader::getHLSL()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000186{
187 return mHlsl;
188}
189
190void Shader::attach()
191{
192 mAttachCount++;
193}
194
195void Shader::detach()
196{
197 mAttachCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000198
199 if (mAttachCount == 0 && mDeleteStatus)
200 {
daniel@transgaming.com95124342010-04-29 03:38:58 +0000201 mContext->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000202 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000203}
204
205bool Shader::isAttached() const
206{
207 return mAttachCount > 0;
208}
209
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000210bool Shader::isFlaggedForDeletion() const
211{
212 return mDeleteStatus;
213}
214
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000215void Shader::flagForDeletion()
216{
217 mDeleteStatus = true;
218}
219
220void Shader::releaseCompiler()
221{
222 ShDestruct(mFragmentCompiler);
223 ShDestruct(mVertexCompiler);
224
225 mFragmentCompiler = NULL;
226 mVertexCompiler = NULL;
alokp@chromium.org90033b92010-05-24 15:02:43 +0000227
228 ShFinalize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000229}
230
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000231void Shader::parseVaryings()
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000232{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000233 if (mHlsl)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000234 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000235 const char *input = strstr(mHlsl, "// Varyings") + 12;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000236
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000237 while(true)
238 {
239 char varyingType[256];
240 char varyingName[256];
241
242 int matches = sscanf(input, "static %s %s", varyingType, varyingName);
243
244 if (matches != 2)
245 {
246 break;
247 }
248
249 char *array = strstr(varyingName, "[");
250 int size = 1;
251
252 if (array)
253 {
254 size = atoi(array + 1);
255 *array = '\0';
256 }
257
258 varyings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
259
260 input = strstr(input, ";") + 2;
261 }
262
263 mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
264 mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
265 }
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000266}
267
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000268void Shader::compileToHLSL(void *compiler)
269{
270 if (isCompiled() || !mSource)
271 {
272 return;
273 }
274
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000275 TRACE("\n%s", mSource);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000276
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000277 delete[] mInfoLog;
278 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000280 int result = ShCompile(compiler, &mSource, 1, EShOptNone, EDebugOpNone);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000281 const char *obj = ShGetObjectCode(compiler);
282 const char *info = ShGetInfoLog(compiler);
283
284 if (result)
285 {
286 mHlsl = new char[strlen(obj) + 1];
287 strcpy(mHlsl, obj);
288
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000289 TRACE("\n%s", mHlsl);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000290 }
291 else
292 {
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000293 mInfoLog = new char[strlen(info) + 1];
294 strcpy(mInfoLog, info);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000295
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000296 TRACE("\n%s", mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000297 }
298}
299
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000300GLenum Shader::parseType(const std::string &type)
301{
302 if (type == "float")
303 {
304 return GL_FLOAT;
305 }
306 else if (type == "float2")
307 {
308 return GL_FLOAT_VEC2;
309 }
310 else if (type == "float3")
311 {
312 return GL_FLOAT_VEC3;
313 }
314 else if (type == "float4")
315 {
316 return GL_FLOAT_VEC4;
317 }
318 else if (type == "float2x2")
319 {
320 return GL_FLOAT_MAT2;
321 }
322 else if (type == "float3x3")
323 {
324 return GL_FLOAT_MAT3;
325 }
326 else if (type == "float4x4")
327 {
328 return GL_FLOAT_MAT4;
329 }
330 else UNREACHABLE();
331
332 return GL_NONE;
333}
334
335// true if varying x has a higher priority in packing than y
336bool Shader::compareVarying(const Varying &x, const Varying &y)
337{
338 if(x.type == y.type)
339 {
340 return x.size > y.size;
341 }
342
343 switch (x.type)
344 {
345 case GL_FLOAT_MAT4: return true;
346 case GL_FLOAT_MAT2:
347 switch(y.type)
348 {
349 case GL_FLOAT_MAT4: return false;
350 case GL_FLOAT_MAT2: return true;
351 case GL_FLOAT_VEC4: return true;
352 case GL_FLOAT_MAT3: return true;
353 case GL_FLOAT_VEC3: return true;
354 case GL_FLOAT_VEC2: return true;
355 case GL_FLOAT: return true;
356 default: UNREACHABLE();
357 }
358 break;
359 case GL_FLOAT_VEC4:
360 switch(y.type)
361 {
362 case GL_FLOAT_MAT4: return false;
363 case GL_FLOAT_MAT2: return false;
364 case GL_FLOAT_VEC4: return true;
365 case GL_FLOAT_MAT3: return true;
366 case GL_FLOAT_VEC3: return true;
367 case GL_FLOAT_VEC2: return true;
368 case GL_FLOAT: return true;
369 default: UNREACHABLE();
370 }
371 break;
372 case GL_FLOAT_MAT3:
373 switch(y.type)
374 {
375 case GL_FLOAT_MAT4: return false;
376 case GL_FLOAT_MAT2: return false;
377 case GL_FLOAT_VEC4: return false;
378 case GL_FLOAT_MAT3: return true;
379 case GL_FLOAT_VEC3: return true;
380 case GL_FLOAT_VEC2: return true;
381 case GL_FLOAT: return true;
382 default: UNREACHABLE();
383 }
384 break;
385 case GL_FLOAT_VEC3:
386 switch(y.type)
387 {
388 case GL_FLOAT_MAT4: return false;
389 case GL_FLOAT_MAT2: return false;
390 case GL_FLOAT_VEC4: return false;
391 case GL_FLOAT_MAT3: return false;
392 case GL_FLOAT_VEC3: return true;
393 case GL_FLOAT_VEC2: return true;
394 case GL_FLOAT: return true;
395 default: UNREACHABLE();
396 }
397 break;
398 case GL_FLOAT_VEC2:
399 switch(y.type)
400 {
401 case GL_FLOAT_MAT4: return false;
402 case GL_FLOAT_MAT2: return false;
403 case GL_FLOAT_VEC4: return false;
404 case GL_FLOAT_MAT3: return false;
405 case GL_FLOAT_VEC3: return false;
406 case GL_FLOAT_VEC2: return true;
407 case GL_FLOAT: return true;
408 default: UNREACHABLE();
409 }
410 break;
411 case GL_FLOAT: return false;
412 default: UNREACHABLE();
413 }
414
415 return false;
416}
417
daniel@transgaming.com95124342010-04-29 03:38:58 +0000418VertexShader::VertexShader(Context *context, GLuint handle) : Shader(context, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000419{
420}
421
422VertexShader::~VertexShader()
423{
424}
425
426GLenum VertexShader::getType()
427{
428 return GL_VERTEX_SHADER;
429}
430
431void VertexShader::compile()
432{
433 compileToHLSL(mVertexCompiler);
434 parseAttributes();
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000435 parseVaryings();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000436}
437
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000438int VertexShader::getSemanticIndex(const std::string &attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000439{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000440 if (!attributeName.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000441 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000442 int semanticIndex = 0;
443 for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000444 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000445 if (attribute->name == attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000446 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000447 return semanticIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000449
450 semanticIndex += VariableRowCount(attribute->type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000451 }
452 }
453
454 return -1;
455}
456
457void VertexShader::parseAttributes()
458{
459 if (mHlsl)
460 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000461 const char *input = strstr(mHlsl, "// Attributes") + 14;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000462
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000463 while(true)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000464 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000465 char attributeType[256];
466 char attributeName[256];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000467
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000468 int matches = sscanf(input, "static %s _%s", attributeType, attributeName);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000469
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000470 if (matches != 2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000471 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000472 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000473 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000474
475 mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
476
477 input = strstr(input, ";") + 2;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000478 }
479 }
480}
481
daniel@transgaming.com95124342010-04-29 03:38:58 +0000482FragmentShader::FragmentShader(Context *context, GLuint handle) : Shader(context, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000483{
484}
485
486FragmentShader::~FragmentShader()
487{
488}
489
490GLenum FragmentShader::getType()
491{
492 return GL_FRAGMENT_SHADER;
493}
494
495void FragmentShader::compile()
496{
497 compileToHLSL(mFragmentCompiler);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000498 parseVaryings();
499 varyings.sort(compareVarying);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000500}
501}