blob: f95b4c7514eebd82aaff897e5f62bff17dfdef4e [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
11#include "Shader.h"
12
13#include "main.h"
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000014#include "GLSLANG/Shaderlang.h"
15#include "compiler/OutputHLSL.h"
16#include "common/debug.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000017
18namespace gl
19{
20void *Shader::mFragmentCompiler = NULL;
21void *Shader::mVertexCompiler = NULL;
22
23Shader::Shader()
24{
25 mSource = NULL;
26 mHlsl = NULL;
27 mErrors = NULL;
28
29 // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler)
30 if (!mFragmentCompiler)
31 {
32 int result = ShInitialize();
33
34 if (result)
35 {
36 mFragmentCompiler = ShConstructCompiler(EShLangFragment, EDebugOpObjectCode);
37 mVertexCompiler = ShConstructCompiler(EShLangVertex, EDebugOpObjectCode);
38 }
39 }
40
41 mAttachCount = 0;
42 mDeleteStatus = false;
43}
44
45Shader::~Shader()
46{
47 delete[] mSource;
48 delete[] mHlsl;
49 delete[] mErrors;
50}
51
52void Shader::setSource(GLsizei count, const char **string, const GLint *length)
53{
54 delete[] mSource;
55 int totalLength = 0;
56
57 for (int i = 0; i < count; i++)
58 {
59 if (length && length[i] >= 0)
60 {
61 totalLength += length[i];
62 }
63 else
64 {
65 totalLength += (int)strlen(string[i]);
66 }
67 }
68
69 mSource = new char[totalLength + 1];
70 char *code = mSource;
71
72 for (int i = 0; i < count; i++)
73 {
74 int stringLength;
75
76 if (length && length[i] >= 0)
77 {
78 stringLength = length[i];
79 }
80 else
81 {
82 stringLength = (int)strlen(string[i]);
83 }
84
85 strncpy(code, string[i], stringLength);
86 code += stringLength;
87 }
88
89 mSource[totalLength] = '\0';
90}
91
92bool Shader::isCompiled()
93{
94 return mHlsl != NULL;
95}
96
97const char *Shader::linkHLSL()
98{
99 return mHlsl;
100}
101
102void Shader::attach()
103{
104 mAttachCount++;
105}
106
107void Shader::detach()
108{
109 mAttachCount--;
110}
111
112bool Shader::isAttached() const
113{
114 return mAttachCount > 0;
115}
116
117bool Shader::isDeletable() const
118{
119 return mDeleteStatus == true && mAttachCount == 0;
120}
121
122void Shader::flagForDeletion()
123{
124 mDeleteStatus = true;
125}
126
127void Shader::releaseCompiler()
128{
129 ShDestruct(mFragmentCompiler);
130 ShDestruct(mVertexCompiler);
131
132 mFragmentCompiler = NULL;
133 mVertexCompiler = NULL;
134}
135
136void Shader::compileToHLSL(void *compiler)
137{
138 if (isCompiled() || !mSource)
139 {
140 return;
141 }
142
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000143 TRACE("\n%s", mSource);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144
145 delete[] mErrors;
146 mErrors = NULL;
147
148 TBuiltInResource resources;
149
150 resources.maxVertexAttribs = MAX_VERTEX_ATTRIBS;
151 resources.maxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
152 resources.maxVaryingVectors = MAX_VARYING_VECTORS;
153 resources.maxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
154 resources.maxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
155 resources.maxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
156 resources.maxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS;
157 resources.maxDrawBuffers = MAX_DRAW_BUFFERS;
158
159 int result = ShCompile(compiler, &mSource, 1, EShOptNone, &resources, EDebugOpObjectCode);
160 const char *obj = ShGetObjectCode(compiler);
161 const char *info = ShGetInfoLog(compiler);
162
163 if (result)
164 {
165 mHlsl = new char[strlen(obj) + 1];
166 strcpy(mHlsl, obj);
167
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000168 TRACE("\n%s", mHlsl);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000169 }
170 else
171 {
172 mErrors = new char[strlen(info) + 1];
173 strcpy(mErrors, info);
174
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000175 TRACE("\n%s", mErrors);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000176 }
177}
178
179InputMapping::InputMapping()
180{
181 mAttribute = NULL;
182 mSemanticIndex = -1;
183}
184
185InputMapping::InputMapping(const char *attribute, int semanticIndex)
186{
187 mAttribute = new char[strlen(attribute) + 1];
188 strcpy(mAttribute, attribute);
189 mSemanticIndex = semanticIndex;
190}
191
192InputMapping &InputMapping::operator=(const InputMapping &inputMapping)
193{
194 delete[] mAttribute;
195
196 mAttribute = new char[strlen(inputMapping.mAttribute) + 1];
197 strcpy(mAttribute, inputMapping.mAttribute);
198 mSemanticIndex = inputMapping.mSemanticIndex;
199
200 return *this;
201}
202
203InputMapping::~InputMapping()
204{
205 delete[] mAttribute;
206}
207
208VertexShader::VertexShader()
209{
210}
211
212VertexShader::~VertexShader()
213{
214}
215
216GLenum VertexShader::getType()
217{
218 return GL_VERTEX_SHADER;
219}
220
221void VertexShader::compile()
222{
223 compileToHLSL(mVertexCompiler);
224 parseAttributes();
225}
226
227const char *VertexShader::linkHLSL(const char *pixelHLSL)
228{
229 if (mHlsl && pixelHLSL)
230 {
231 const char *input = strstr(pixelHLSL, "struct PS_INPUT");
232 char *output = strstr(mHlsl, "struct VS_OUTPUT");
233
234 while (*input != '}' && output)
235 {
236 char varyingName[100];
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000237 unsigned int semanticIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000238 int matches = sscanf(input, "%s : TEXCOORD%d;", varyingName, &semanticIndex);
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000239
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000240 if (matches == 2 && semanticIndex != sh::HLSL_FRAG_COORD_SEMANTIC)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000241 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000242 ASSERT(semanticIndex < MAX_VARYING_VECTORS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000243 char *varying = strstr(output, varyingName);
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +0000244
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000245 if (varying)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000246 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000247 ASSERT(semanticIndex <= 9); // Single character
248 varying = strstr(varying, " : TEXCOORD0;");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000249 varying[11] = '0' + semanticIndex;
250 }
251 else
252 {
253 return NULL;
254 }
255
256 input = strstr(input, ";");
257 }
258
259 input++;
260 }
261 }
262
263 return mHlsl;
264}
265
266const char *VertexShader::getAttributeName(unsigned int attributeIndex)
267{
268 if (attributeIndex < MAX_VERTEX_ATTRIBS)
269 {
270 return mInputMapping[attributeIndex].mAttribute;
271 }
272
273 return 0;
274}
275
276bool VertexShader::isActiveAttribute(const char *attributeName)
277{
278 return getInputMapping(attributeName) != -1;
279}
280
281int VertexShader::getInputMapping(const char *attributeName)
282{
283 if (attributeName)
284 {
285 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
286 {
287 if (mInputMapping[index].mAttribute && strcmp(mInputMapping[index].mAttribute, attributeName) == 0)
288 {
289 return mInputMapping[index].mSemanticIndex;
290 }
291 }
292 }
293
294 return -1;
295}
296
297void VertexShader::parseAttributes()
298{
299 if (mHlsl)
300 {
301 const char *input = strstr(mHlsl, "struct VS_INPUT");
302
303 for (int attributeIndex = 0; *input != '}'; input++)
304 {
305 char attributeName[100];
306 int semanticIndex;
307
308 int matches = sscanf(input, "%s : TEXCOORD%d;", attributeName, &semanticIndex);
309
310 if (matches == 2)
311 {
312 ASSERT(attributeIndex < MAX_VERTEX_ATTRIBS);
313 mInputMapping[attributeIndex] = InputMapping(attributeName, semanticIndex);
314 attributeIndex++;
315
316 input = strstr(input, ";");
317 }
318 }
319 }
320}
321
322FragmentShader::FragmentShader()
323{
324}
325
326FragmentShader::~FragmentShader()
327{
328}
329
330GLenum FragmentShader::getType()
331{
332 return GL_FRAGMENT_SHADER;
333}
334
335void FragmentShader::compile()
336{
337 compileToHLSL(mFragmentCompiler);
338}
339}