blob: 10a4b75732d668f6bca1a42a1e602c483d9f3a01 [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.orgea0e1af2010-03-22 19:33:14 +000013#include "GLSLANG/Shaderlang.h"
14#include "compiler/OutputHLSL.h"
15#include "common/debug.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000016
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000017#include "libGLESv2/main.h"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000018#include "libGLESv2/utilities.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000019
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000020namespace gl
21{
22void *Shader::mFragmentCompiler = NULL;
23void *Shader::mVertexCompiler = NULL;
24
daniel@transgaming.com95124342010-04-29 03:38:58 +000025Shader::Shader(Context *context, GLuint handle) : mHandle(handle), mContext(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000026{
27 mSource = NULL;
28 mHlsl = NULL;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000029 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000030
31 // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler)
32 if (!mFragmentCompiler)
33 {
34 int result = ShInitialize();
35
36 if (result)
37 {
38 mFragmentCompiler = ShConstructCompiler(EShLangFragment, EDebugOpObjectCode);
39 mVertexCompiler = ShConstructCompiler(EShLangVertex, EDebugOpObjectCode);
40 }
41 }
42
43 mAttachCount = 0;
44 mDeleteStatus = false;
45}
46
47Shader::~Shader()
48{
49 delete[] mSource;
50 delete[] mHlsl;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000051 delete[] mInfoLog;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000052}
53
daniel@transgaming.com6c785212010-03-30 03:36:17 +000054GLuint Shader::getHandle() const
55{
56 return mHandle;
57}
58
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000059void Shader::setSource(GLsizei count, const char **string, const GLint *length)
60{
61 delete[] mSource;
62 int totalLength = 0;
63
64 for (int i = 0; i < count; i++)
65 {
66 if (length && length[i] >= 0)
67 {
68 totalLength += length[i];
69 }
70 else
71 {
72 totalLength += (int)strlen(string[i]);
73 }
74 }
75
76 mSource = new char[totalLength + 1];
77 char *code = mSource;
78
79 for (int i = 0; i < count; i++)
80 {
81 int stringLength;
82
83 if (length && length[i] >= 0)
84 {
85 stringLength = length[i];
86 }
87 else
88 {
89 stringLength = (int)strlen(string[i]);
90 }
91
92 strncpy(code, string[i], stringLength);
93 code += stringLength;
94 }
95
96 mSource[totalLength] = '\0';
97}
98
daniel@transgaming.comcba50572010-03-28 19:36:09 +000099int Shader::getInfoLogLength() const
100{
101 if (!mInfoLog)
102 {
103 return 0;
104 }
105 else
106 {
107 return strlen(mInfoLog) + 1;
108 }
109}
110
111void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
112{
113 int index = 0;
114
115 if (mInfoLog)
116 {
117 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
118 {
119 infoLog[index] = mInfoLog[index];
120 index++;
121 }
122 }
123
124 if (bufSize)
125 {
126 infoLog[index] = '\0';
127 }
128
129 if (length)
130 {
131 *length = index;
132 }
133}
134
135int Shader::getSourceLength() const
136{
137 if (!mSource)
138 {
139 return 0;
140 }
141 else
142 {
143 return strlen(mSource) + 1;
144 }
145}
146
147void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
148{
149 int index = 0;
150
151 if (mSource)
152 {
daniel@transgaming.com41187f12010-04-01 13:39:29 +0000153 while (index < bufSize - 1 && index < (int)strlen(mSource))
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000154 {
155 source[index] = mSource[index];
156 index++;
157 }
158 }
159
160 if (bufSize)
161 {
162 source[index] = '\0';
163 }
164
165 if (length)
166 {
167 *length = index;
168 }
169}
170
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171bool Shader::isCompiled()
172{
173 return mHlsl != NULL;
174}
175
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000176const char *Shader::getHLSL()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177{
178 return mHlsl;
179}
180
181void Shader::attach()
182{
183 mAttachCount++;
184}
185
186void Shader::detach()
187{
188 mAttachCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000189
190 if (mAttachCount == 0 && mDeleteStatus)
191 {
daniel@transgaming.com95124342010-04-29 03:38:58 +0000192 mContext->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000193 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000194}
195
196bool Shader::isAttached() const
197{
198 return mAttachCount > 0;
199}
200
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000201bool Shader::isFlaggedForDeletion() const
202{
203 return mDeleteStatus;
204}
205
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000206void Shader::flagForDeletion()
207{
208 mDeleteStatus = true;
209}
210
211void Shader::releaseCompiler()
212{
213 ShDestruct(mFragmentCompiler);
214 ShDestruct(mVertexCompiler);
215
216 mFragmentCompiler = NULL;
217 mVertexCompiler = NULL;
alokp@chromium.org90033b92010-05-24 15:02:43 +0000218
219 ShFinalize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000220}
221
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000222void Shader::parseVaryings()
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000223{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000224 if (mHlsl)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000225 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000226 const char *input = strstr(mHlsl, "// Varyings") + 12;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000227
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000228 while(true)
229 {
230 char varyingType[256];
231 char varyingName[256];
232
233 int matches = sscanf(input, "static %s %s", varyingType, varyingName);
234
235 if (matches != 2)
236 {
237 break;
238 }
239
240 char *array = strstr(varyingName, "[");
241 int size = 1;
242
243 if (array)
244 {
245 size = atoi(array + 1);
246 *array = '\0';
247 }
248
249 varyings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
250
251 input = strstr(input, ";") + 2;
252 }
253
254 mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
255 mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
256 }
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000257}
258
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259void Shader::compileToHLSL(void *compiler)
260{
261 if (isCompiled() || !mSource)
262 {
263 return;
264 }
265
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000266 TRACE("\n%s", mSource);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000267
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000268 delete[] mInfoLog;
269 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000270
271 TBuiltInResource resources;
272
273 resources.maxVertexAttribs = MAX_VERTEX_ATTRIBS;
274 resources.maxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
275 resources.maxVaryingVectors = MAX_VARYING_VECTORS;
276 resources.maxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
277 resources.maxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
278 resources.maxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
279 resources.maxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS;
280 resources.maxDrawBuffers = MAX_DRAW_BUFFERS;
281
282 int result = ShCompile(compiler, &mSource, 1, EShOptNone, &resources, EDebugOpObjectCode);
283 const char *obj = ShGetObjectCode(compiler);
284 const char *info = ShGetInfoLog(compiler);
285
286 if (result)
287 {
288 mHlsl = new char[strlen(obj) + 1];
289 strcpy(mHlsl, obj);
290
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000291 TRACE("\n%s", mHlsl);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000292 }
293 else
294 {
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000295 mInfoLog = new char[strlen(info) + 1];
296 strcpy(mInfoLog, info);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000297
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000298 TRACE("\n%s", mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000299 }
300}
301
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000302GLenum Shader::parseType(const std::string &type)
303{
304 if (type == "float")
305 {
306 return GL_FLOAT;
307 }
308 else if (type == "float2")
309 {
310 return GL_FLOAT_VEC2;
311 }
312 else if (type == "float3")
313 {
314 return GL_FLOAT_VEC3;
315 }
316 else if (type == "float4")
317 {
318 return GL_FLOAT_VEC4;
319 }
320 else if (type == "float2x2")
321 {
322 return GL_FLOAT_MAT2;
323 }
324 else if (type == "float3x3")
325 {
326 return GL_FLOAT_MAT3;
327 }
328 else if (type == "float4x4")
329 {
330 return GL_FLOAT_MAT4;
331 }
332 else UNREACHABLE();
333
334 return GL_NONE;
335}
336
337// true if varying x has a higher priority in packing than y
338bool Shader::compareVarying(const Varying &x, const Varying &y)
339{
340 if(x.type == y.type)
341 {
342 return x.size > y.size;
343 }
344
345 switch (x.type)
346 {
347 case GL_FLOAT_MAT4: return true;
348 case GL_FLOAT_MAT2:
349 switch(y.type)
350 {
351 case GL_FLOAT_MAT4: return false;
352 case GL_FLOAT_MAT2: return true;
353 case GL_FLOAT_VEC4: return true;
354 case GL_FLOAT_MAT3: return true;
355 case GL_FLOAT_VEC3: return true;
356 case GL_FLOAT_VEC2: return true;
357 case GL_FLOAT: return true;
358 default: UNREACHABLE();
359 }
360 break;
361 case GL_FLOAT_VEC4:
362 switch(y.type)
363 {
364 case GL_FLOAT_MAT4: return false;
365 case GL_FLOAT_MAT2: return false;
366 case GL_FLOAT_VEC4: return true;
367 case GL_FLOAT_MAT3: return true;
368 case GL_FLOAT_VEC3: return true;
369 case GL_FLOAT_VEC2: return true;
370 case GL_FLOAT: return true;
371 default: UNREACHABLE();
372 }
373 break;
374 case GL_FLOAT_MAT3:
375 switch(y.type)
376 {
377 case GL_FLOAT_MAT4: return false;
378 case GL_FLOAT_MAT2: return false;
379 case GL_FLOAT_VEC4: return false;
380 case GL_FLOAT_MAT3: return true;
381 case GL_FLOAT_VEC3: return true;
382 case GL_FLOAT_VEC2: return true;
383 case GL_FLOAT: return true;
384 default: UNREACHABLE();
385 }
386 break;
387 case GL_FLOAT_VEC3:
388 switch(y.type)
389 {
390 case GL_FLOAT_MAT4: return false;
391 case GL_FLOAT_MAT2: return false;
392 case GL_FLOAT_VEC4: return false;
393 case GL_FLOAT_MAT3: return false;
394 case GL_FLOAT_VEC3: return true;
395 case GL_FLOAT_VEC2: return true;
396 case GL_FLOAT: return true;
397 default: UNREACHABLE();
398 }
399 break;
400 case GL_FLOAT_VEC2:
401 switch(y.type)
402 {
403 case GL_FLOAT_MAT4: return false;
404 case GL_FLOAT_MAT2: return false;
405 case GL_FLOAT_VEC4: return false;
406 case GL_FLOAT_MAT3: return false;
407 case GL_FLOAT_VEC3: return false;
408 case GL_FLOAT_VEC2: return true;
409 case GL_FLOAT: return true;
410 default: UNREACHABLE();
411 }
412 break;
413 case GL_FLOAT: return false;
414 default: UNREACHABLE();
415 }
416
417 return false;
418}
419
daniel@transgaming.com95124342010-04-29 03:38:58 +0000420VertexShader::VertexShader(Context *context, GLuint handle) : Shader(context, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000421{
422}
423
424VertexShader::~VertexShader()
425{
426}
427
428GLenum VertexShader::getType()
429{
430 return GL_VERTEX_SHADER;
431}
432
433void VertexShader::compile()
434{
435 compileToHLSL(mVertexCompiler);
436 parseAttributes();
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000437 parseVaryings();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000438}
439
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000440int VertexShader::getSemanticIndex(const std::string &attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000441{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000442 if (!attributeName.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000443 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000444 int semanticIndex = 0;
445 for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000446 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000447 if (attribute->name == attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000449 return semanticIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000450 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000451
452 semanticIndex += VariableRowCount(attribute->type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000453 }
454 }
455
456 return -1;
457}
458
459void VertexShader::parseAttributes()
460{
461 if (mHlsl)
462 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000463 const char *input = strstr(mHlsl, "// Attributes") + 14;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000464
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000465 while(true)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000466 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000467 char attributeType[256];
468 char attributeName[256];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000469
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000470 int matches = sscanf(input, "static %s _%s", attributeType, attributeName);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000471
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000472 if (matches != 2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000473 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000474 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000475 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000476
477 mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
478
479 input = strstr(input, ";") + 2;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000480 }
481 }
482}
483
daniel@transgaming.com95124342010-04-29 03:38:58 +0000484FragmentShader::FragmentShader(Context *context, GLuint handle) : Shader(context, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000485{
486}
487
488FragmentShader::~FragmentShader()
489{
490}
491
492GLenum FragmentShader::getType()
493{
494 return GL_FRAGMENT_SHADER;
495}
496
497void FragmentShader::compile()
498{
499 compileToHLSL(mFragmentCompiler);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000500 parseVaryings();
501 varyings.sort(compareVarying);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000502}
503}