blob: 1fae330d6e3e5c7c4f1ebc044f454e976a9be81d [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
219void Shader::compileToHLSL(void *compiler)
220{
221 if (isCompiled() || !mSource)
222 {
223 return;
224 }
225
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000226 TRACE("\n%s", mSource);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000227
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000228 delete[] mInfoLog;
229 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000230
231 TBuiltInResource resources;
232
233 resources.maxVertexAttribs = MAX_VERTEX_ATTRIBS;
234 resources.maxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
235 resources.maxVaryingVectors = MAX_VARYING_VECTORS;
236 resources.maxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
237 resources.maxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
238 resources.maxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
239 resources.maxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS;
240 resources.maxDrawBuffers = MAX_DRAW_BUFFERS;
241
242 int result = ShCompile(compiler, &mSource, 1, EShOptNone, &resources, EDebugOpObjectCode);
243 const char *obj = ShGetObjectCode(compiler);
244 const char *info = ShGetInfoLog(compiler);
245
246 if (result)
247 {
248 mHlsl = new char[strlen(obj) + 1];
249 strcpy(mHlsl, obj);
250
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000251 TRACE("\n%s", mHlsl);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000252 }
253 else
254 {
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000255 mInfoLog = new char[strlen(info) + 1];
256 strcpy(mInfoLog, info);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000257
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000258 TRACE("\n%s", mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259 }
260}
261
262InputMapping::InputMapping()
263{
264 mAttribute = NULL;
265 mSemanticIndex = -1;
266}
267
268InputMapping::InputMapping(const char *attribute, int semanticIndex)
269{
270 mAttribute = new char[strlen(attribute) + 1];
271 strcpy(mAttribute, attribute);
272 mSemanticIndex = semanticIndex;
273}
274
275InputMapping &InputMapping::operator=(const InputMapping &inputMapping)
276{
277 delete[] mAttribute;
278
279 mAttribute = new char[strlen(inputMapping.mAttribute) + 1];
280 strcpy(mAttribute, inputMapping.mAttribute);
281 mSemanticIndex = inputMapping.mSemanticIndex;
282
283 return *this;
284}
285
286InputMapping::~InputMapping()
287{
288 delete[] mAttribute;
289}
290
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000291VertexShader::VertexShader(GLuint handle) : Shader(handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000292{
293}
294
295VertexShader::~VertexShader()
296{
297}
298
299GLenum VertexShader::getType()
300{
301 return GL_VERTEX_SHADER;
302}
303
304void VertexShader::compile()
305{
306 compileToHLSL(mVertexCompiler);
307 parseAttributes();
308}
309
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000310const char *VertexShader::getAttributeName(unsigned int attributeIndex)
311{
312 if (attributeIndex < MAX_VERTEX_ATTRIBS)
313 {
314 return mInputMapping[attributeIndex].mAttribute;
315 }
316
317 return 0;
318}
319
320bool VertexShader::isActiveAttribute(const char *attributeName)
321{
322 return getInputMapping(attributeName) != -1;
323}
324
325int VertexShader::getInputMapping(const char *attributeName)
326{
327 if (attributeName)
328 {
329 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
330 {
331 if (mInputMapping[index].mAttribute && strcmp(mInputMapping[index].mAttribute, attributeName) == 0)
332 {
333 return mInputMapping[index].mSemanticIndex;
334 }
335 }
336 }
337
338 return -1;
339}
340
341void VertexShader::parseAttributes()
342{
343 if (mHlsl)
344 {
345 const char *input = strstr(mHlsl, "struct VS_INPUT");
346
347 for (int attributeIndex = 0; *input != '}'; input++)
348 {
349 char attributeName[100];
350 int semanticIndex;
351
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000352 int matches = sscanf(input, "_%s : TEXCOORD%d;", attributeName, &semanticIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000353
354 if (matches == 2)
355 {
356 ASSERT(attributeIndex < MAX_VERTEX_ATTRIBS);
357 mInputMapping[attributeIndex] = InputMapping(attributeName, semanticIndex);
358 attributeIndex++;
359
360 input = strstr(input, ";");
361 }
362 }
363 }
364}
365
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000366FragmentShader::FragmentShader(GLuint handle) : Shader(handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000367{
368}
369
370FragmentShader::~FragmentShader()
371{
372}
373
374GLenum FragmentShader::getType()
375{
376 return GL_FRAGMENT_SHADER;
377}
378
379void FragmentShader::compile()
380{
381 compileToHLSL(mFragmentCompiler);
382}
383}