blob: 04682a40b3fe1f91f4e6b1f91668cba699357157 [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 {
37 mFragmentCompiler = ShConstructCompiler(EShLangFragment, EDebugOpObjectCode);
38 mVertexCompiler = ShConstructCompiler(EShLangVertex, EDebugOpObjectCode);
39 }
40 }
41
42 mAttachCount = 0;
43 mDeleteStatus = false;
44}
45
46Shader::~Shader()
47{
48 delete[] mSource;
49 delete[] mHlsl;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000050 delete[] mInfoLog;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000051}
52
daniel@transgaming.com6c785212010-03-30 03:36:17 +000053GLuint Shader::getHandle() const
54{
55 return mHandle;
56}
57
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000058void Shader::setSource(GLsizei count, const char **string, const GLint *length)
59{
60 delete[] mSource;
61 int totalLength = 0;
62
63 for (int i = 0; i < count; i++)
64 {
65 if (length && length[i] >= 0)
66 {
67 totalLength += length[i];
68 }
69 else
70 {
71 totalLength += (int)strlen(string[i]);
72 }
73 }
74
75 mSource = new char[totalLength + 1];
76 char *code = mSource;
77
78 for (int i = 0; i < count; i++)
79 {
80 int stringLength;
81
82 if (length && length[i] >= 0)
83 {
84 stringLength = length[i];
85 }
86 else
87 {
88 stringLength = (int)strlen(string[i]);
89 }
90
91 strncpy(code, string[i], stringLength);
92 code += stringLength;
93 }
94
95 mSource[totalLength] = '\0';
96}
97
daniel@transgaming.comcba50572010-03-28 19:36:09 +000098int Shader::getInfoLogLength() const
99{
100 if (!mInfoLog)
101 {
102 return 0;
103 }
104 else
105 {
106 return strlen(mInfoLog) + 1;
107 }
108}
109
110void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
111{
112 int index = 0;
113
114 if (mInfoLog)
115 {
116 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
117 {
118 infoLog[index] = mInfoLog[index];
119 index++;
120 }
121 }
122
123 if (bufSize)
124 {
125 infoLog[index] = '\0';
126 }
127
128 if (length)
129 {
130 *length = index;
131 }
132}
133
134int Shader::getSourceLength() const
135{
136 if (!mSource)
137 {
138 return 0;
139 }
140 else
141 {
142 return strlen(mSource) + 1;
143 }
144}
145
146void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
147{
148 int index = 0;
149
150 if (mSource)
151 {
daniel@transgaming.com41187f12010-04-01 13:39:29 +0000152 while (index < bufSize - 1 && index < (int)strlen(mSource))
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000153 {
154 source[index] = mSource[index];
155 index++;
156 }
157 }
158
159 if (bufSize)
160 {
161 source[index] = '\0';
162 }
163
164 if (length)
165 {
166 *length = index;
167 }
168}
169
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000170bool Shader::isCompiled()
171{
172 return mHlsl != NULL;
173}
174
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000175const char *Shader::getHLSL()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000176{
177 return mHlsl;
178}
179
180void Shader::attach()
181{
182 mAttachCount++;
183}
184
185void Shader::detach()
186{
187 mAttachCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000188
189 if (mAttachCount == 0 && mDeleteStatus)
190 {
daniel@transgaming.com95124342010-04-29 03:38:58 +0000191 mContext->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000192 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000193}
194
195bool Shader::isAttached() const
196{
197 return mAttachCount > 0;
198}
199
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000200bool Shader::isFlaggedForDeletion() const
201{
202 return mDeleteStatus;
203}
204
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000205void Shader::flagForDeletion()
206{
207 mDeleteStatus = true;
208}
209
210void Shader::releaseCompiler()
211{
212 ShDestruct(mFragmentCompiler);
213 ShDestruct(mVertexCompiler);
214
215 mFragmentCompiler = NULL;
216 mVertexCompiler = NULL;
alokp@chromium.org90033b92010-05-24 15:02:43 +0000217
218 ShFinalize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000219}
220
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000221void Shader::parseVaryings()
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000222{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000223 if (mHlsl)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000224 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000225 const char *input = strstr(mHlsl, "// Varyings") + 12;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000226
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000227 while(true)
228 {
229 char varyingType[256];
230 char varyingName[256];
231
232 int matches = sscanf(input, "static %s %s", varyingType, varyingName);
233
234 if (matches != 2)
235 {
236 break;
237 }
238
239 char *array = strstr(varyingName, "[");
240 int size = 1;
241
242 if (array)
243 {
244 size = atoi(array + 1);
245 *array = '\0';
246 }
247
248 varyings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
249
250 input = strstr(input, ";") + 2;
251 }
252
253 mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
254 mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
255 }
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000256}
257
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000258void Shader::compileToHLSL(void *compiler)
259{
260 if (isCompiled() || !mSource)
261 {
262 return;
263 }
264
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000265 TRACE("\n%s", mSource);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000266
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000267 delete[] mInfoLog;
268 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000269
270 TBuiltInResource resources;
271
272 resources.maxVertexAttribs = MAX_VERTEX_ATTRIBS;
273 resources.maxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
274 resources.maxVaryingVectors = MAX_VARYING_VECTORS;
275 resources.maxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
276 resources.maxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
277 resources.maxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
278 resources.maxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS;
279 resources.maxDrawBuffers = MAX_DRAW_BUFFERS;
280
281 int result = ShCompile(compiler, &mSource, 1, EShOptNone, &resources, EDebugOpObjectCode);
282 const char *obj = ShGetObjectCode(compiler);
283 const char *info = ShGetInfoLog(compiler);
284
285 if (result)
286 {
287 mHlsl = new char[strlen(obj) + 1];
288 strcpy(mHlsl, obj);
289
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000290 TRACE("\n%s", mHlsl);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000291 }
292 else
293 {
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000294 mInfoLog = new char[strlen(info) + 1];
295 strcpy(mInfoLog, info);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000297 TRACE("\n%s", mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000298 }
299}
300
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000301GLenum Shader::parseType(const std::string &type)
302{
303 if (type == "float")
304 {
305 return GL_FLOAT;
306 }
307 else if (type == "float2")
308 {
309 return GL_FLOAT_VEC2;
310 }
311 else if (type == "float3")
312 {
313 return GL_FLOAT_VEC3;
314 }
315 else if (type == "float4")
316 {
317 return GL_FLOAT_VEC4;
318 }
319 else if (type == "float2x2")
320 {
321 return GL_FLOAT_MAT2;
322 }
323 else if (type == "float3x3")
324 {
325 return GL_FLOAT_MAT3;
326 }
327 else if (type == "float4x4")
328 {
329 return GL_FLOAT_MAT4;
330 }
331 else UNREACHABLE();
332
333 return GL_NONE;
334}
335
336// true if varying x has a higher priority in packing than y
337bool Shader::compareVarying(const Varying &x, const Varying &y)
338{
339 if(x.type == y.type)
340 {
341 return x.size > y.size;
342 }
343
344 switch (x.type)
345 {
346 case GL_FLOAT_MAT4: return true;
347 case GL_FLOAT_MAT2:
348 switch(y.type)
349 {
350 case GL_FLOAT_MAT4: return false;
351 case GL_FLOAT_MAT2: return true;
352 case GL_FLOAT_VEC4: return true;
353 case GL_FLOAT_MAT3: return true;
354 case GL_FLOAT_VEC3: return true;
355 case GL_FLOAT_VEC2: return true;
356 case GL_FLOAT: return true;
357 default: UNREACHABLE();
358 }
359 break;
360 case GL_FLOAT_VEC4:
361 switch(y.type)
362 {
363 case GL_FLOAT_MAT4: return false;
364 case GL_FLOAT_MAT2: return false;
365 case GL_FLOAT_VEC4: return true;
366 case GL_FLOAT_MAT3: return true;
367 case GL_FLOAT_VEC3: return true;
368 case GL_FLOAT_VEC2: return true;
369 case GL_FLOAT: return true;
370 default: UNREACHABLE();
371 }
372 break;
373 case GL_FLOAT_MAT3:
374 switch(y.type)
375 {
376 case GL_FLOAT_MAT4: return false;
377 case GL_FLOAT_MAT2: return false;
378 case GL_FLOAT_VEC4: return false;
379 case GL_FLOAT_MAT3: return true;
380 case GL_FLOAT_VEC3: return true;
381 case GL_FLOAT_VEC2: return true;
382 case GL_FLOAT: return true;
383 default: UNREACHABLE();
384 }
385 break;
386 case GL_FLOAT_VEC3:
387 switch(y.type)
388 {
389 case GL_FLOAT_MAT4: return false;
390 case GL_FLOAT_MAT2: return false;
391 case GL_FLOAT_VEC4: return false;
392 case GL_FLOAT_MAT3: return false;
393 case GL_FLOAT_VEC3: return true;
394 case GL_FLOAT_VEC2: return true;
395 case GL_FLOAT: return true;
396 default: UNREACHABLE();
397 }
398 break;
399 case GL_FLOAT_VEC2:
400 switch(y.type)
401 {
402 case GL_FLOAT_MAT4: return false;
403 case GL_FLOAT_MAT2: return false;
404 case GL_FLOAT_VEC4: return false;
405 case GL_FLOAT_MAT3: return false;
406 case GL_FLOAT_VEC3: return false;
407 case GL_FLOAT_VEC2: return true;
408 case GL_FLOAT: return true;
409 default: UNREACHABLE();
410 }
411 break;
412 case GL_FLOAT: return false;
413 default: UNREACHABLE();
414 }
415
416 return false;
417}
418
daniel@transgaming.com95124342010-04-29 03:38:58 +0000419VertexShader::VertexShader(Context *context, GLuint handle) : Shader(context, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420{
421}
422
423VertexShader::~VertexShader()
424{
425}
426
427GLenum VertexShader::getType()
428{
429 return GL_VERTEX_SHADER;
430}
431
432void VertexShader::compile()
433{
434 compileToHLSL(mVertexCompiler);
435 parseAttributes();
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000436 parseVaryings();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000437}
438
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000439int VertexShader::getSemanticIndex(const std::string &attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000440{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000441 if (!attributeName.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000443 int semanticIndex = 0;
444 for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000445 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000446 if (attribute->name == attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000447 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000448 return semanticIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000449 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000450
451 semanticIndex += VariableRowCount(attribute->type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000452 }
453 }
454
455 return -1;
456}
457
458void VertexShader::parseAttributes()
459{
460 if (mHlsl)
461 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000462 const char *input = strstr(mHlsl, "// Attributes") + 14;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000463
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000464 while(true)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000465 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000466 char attributeType[256];
467 char attributeName[256];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000468
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000469 int matches = sscanf(input, "static %s _%s", attributeType, attributeName);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000470
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000471 if (matches != 2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000472 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000473 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000474 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000475
476 mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
477
478 input = strstr(input, ";") + 2;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000479 }
480 }
481}
482
daniel@transgaming.com95124342010-04-29 03:38:58 +0000483FragmentShader::FragmentShader(Context *context, GLuint handle) : Shader(context, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000484{
485}
486
487FragmentShader::~FragmentShader()
488{
489}
490
491GLenum FragmentShader::getType()
492{
493 return GL_FRAGMENT_SHADER;
494}
495
496void FragmentShader::compile()
497{
498 compileToHLSL(mFragmentCompiler);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000499 parseVaryings();
500 varyings.sort(compareVarying);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000501}
502}