blob: 2abbd61ffef0e9e17c4aea050c30287e3526fe97 [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"
18
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000019namespace gl
20{
21void *Shader::mFragmentCompiler = NULL;
22void *Shader::mVertexCompiler = NULL;
23
daniel@transgaming.com6c785212010-03-30 03:36:17 +000024Shader::Shader(GLuint handle) : mHandle(handle)
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--;
188}
189
190bool Shader::isAttached() const
191{
192 return mAttachCount > 0;
193}
194
195bool Shader::isDeletable() const
196{
197 return mDeleteStatus == true && 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;
217}
218
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000219GLenum Shader::parseAttributeType(const std::string &type)
220{
221 if (type == "float")
222 {
223 return GL_FLOAT;
224 }
225 else if (type == "float2")
226 {
227 return GL_FLOAT_VEC2;
228 }
229 else if (type == "float3")
230 {
231 return GL_FLOAT_VEC3;
232 }
233 else if (type == "float4")
234 {
235 return GL_FLOAT_VEC4;
236 }
237 else if (type == "float2x2")
238 {
239 return GL_FLOAT_MAT2;
240 }
241 else if (type == "float3x3")
242 {
243 return GL_FLOAT_MAT3;
244 }
245 else if (type == "float4x4")
246 {
247 return GL_FLOAT_MAT4;
248 }
249 else UNREACHABLE();
250
251 return GL_NONE;
252}
253
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000254void Shader::compileToHLSL(void *compiler)
255{
256 if (isCompiled() || !mSource)
257 {
258 return;
259 }
260
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000261 TRACE("\n%s", mSource);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000262
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000263 delete[] mInfoLog;
264 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000265
266 TBuiltInResource resources;
267
268 resources.maxVertexAttribs = MAX_VERTEX_ATTRIBS;
269 resources.maxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
270 resources.maxVaryingVectors = MAX_VARYING_VECTORS;
271 resources.maxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
272 resources.maxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
273 resources.maxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
274 resources.maxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS;
275 resources.maxDrawBuffers = MAX_DRAW_BUFFERS;
276
277 int result = ShCompile(compiler, &mSource, 1, EShOptNone, &resources, EDebugOpObjectCode);
278 const char *obj = ShGetObjectCode(compiler);
279 const char *info = ShGetInfoLog(compiler);
280
281 if (result)
282 {
283 mHlsl = new char[strlen(obj) + 1];
284 strcpy(mHlsl, obj);
285
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000286 TRACE("\n%s", mHlsl);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000287 }
288 else
289 {
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000290 mInfoLog = new char[strlen(info) + 1];
291 strcpy(mInfoLog, info);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000292
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000293 TRACE("\n%s", mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000294 }
295}
296
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000297VertexShader::VertexShader(GLuint handle) : Shader(handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000298{
299}
300
301VertexShader::~VertexShader()
302{
303}
304
305GLenum VertexShader::getType()
306{
307 return GL_VERTEX_SHADER;
308}
309
310void VertexShader::compile()
311{
312 compileToHLSL(mVertexCompiler);
313 parseAttributes();
314}
315
daniel@transgaming.com85423182010-04-22 13:35:27 +0000316const Attribute &VertexShader::getAttribute(unsigned int semanticIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000317{
daniel@transgaming.com85423182010-04-22 13:35:27 +0000318 ASSERT(semanticIndex < MAX_VERTEX_ATTRIBS + 1);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000319
daniel@transgaming.com85423182010-04-22 13:35:27 +0000320 return mAttribute[semanticIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000321}
322
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000323int VertexShader::getSemanticIndex(const std::string &attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000324{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000325 if (!attributeName.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000326 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000327 for (int semanticIndex = 0; semanticIndex < MAX_VERTEX_ATTRIBS; semanticIndex++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000328 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000329 if (mAttribute[semanticIndex].name == attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000331 return semanticIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000332 }
333 }
334 }
335
336 return -1;
337}
338
339void VertexShader::parseAttributes()
340{
341 if (mHlsl)
342 {
343 const char *input = strstr(mHlsl, "struct VS_INPUT");
344
345 for (int attributeIndex = 0; *input != '}'; input++)
346 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000347 char attributeType[100];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000348 char attributeName[100];
349 int semanticIndex;
350
daniel@transgaming.com85423182010-04-22 13:35:27 +0000351 int matches = sscanf(input, "%s _%s : TEXCOORD%d;", attributeType, attributeName, &semanticIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352
daniel@transgaming.com85423182010-04-22 13:35:27 +0000353 if (matches == 3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000354 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000355 if (semanticIndex < MAX_VERTEX_ATTRIBS + 1)
356 {
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000357 mAttribute[semanticIndex].type = parseAttributeType(attributeType);
daniel@transgaming.com85423182010-04-22 13:35:27 +0000358 mAttribute[semanticIndex].name = attributeName;
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000359 }
360 else
361 {
362 break;
363 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000364
365 input = strstr(input, ";");
366 }
367 }
368 }
369}
370
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000371FragmentShader::FragmentShader(GLuint handle) : Shader(handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000372{
373}
374
375FragmentShader::~FragmentShader()
376{
377}
378
379GLenum FragmentShader::getType()
380{
381 return GL_FRAGMENT_SHADER;
382}
383
384void FragmentShader::compile()
385{
386 compileToHLSL(mFragmentCompiler);
387}
388}