blob: aa743194d559cd0c2cccd6a09cddffaa3662dd54 [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// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010#include "libGLESv2/Program.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000011
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000012#include "common/debug.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000013
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000014#include "libGLESv2/main.h"
15#include "libGLESv2/Shader.h"
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000016#include "libGLESv2/utilities.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000017
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000018namespace gl
19{
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000020Uniform::Uniform(GLenum type, const std::string &name, unsigned int arraySize) : type(type), name(name), arraySize(arraySize)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021{
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000022 int bytes = UniformTypeSize(type) * arraySize;
23
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000024 this->data = new unsigned char[bytes];
25 memset(this->data, 0, bytes);
26}
27
28Uniform::~Uniform()
29{
30 delete[] data;
31}
32
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +000033UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
34 : name(name), element(element), index(index)
35{
36}
37
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000038Program::Program()
39{
40 mFragmentShader = NULL;
41 mVertexShader = NULL;
42
43 mPixelExecutable = NULL;
44 mVertexExecutable = NULL;
45 mConstantTablePS = NULL;
46 mConstantTableVS = NULL;
47
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +000048 mPixelHLSL = NULL;
49 mVertexHLSL = NULL;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000050 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +000051 mValidated = false;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000052
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000053 unlink();
54
55 mDeleteStatus = false;
56}
57
58Program::~Program()
59{
60 unlink(true);
61}
62
63bool Program::attachShader(Shader *shader)
64{
65 if (shader->getType() == GL_VERTEX_SHADER)
66 {
67 if (mVertexShader)
68 {
69 return false;
70 }
71
72 mVertexShader = (VertexShader*)shader;
73 mVertexShader->attach();
74 }
75 else if (shader->getType() == GL_FRAGMENT_SHADER)
76 {
77 if (mFragmentShader)
78 {
79 return false;
80 }
81
82 mFragmentShader = (FragmentShader*)shader;
83 mFragmentShader->attach();
84 }
85 else UNREACHABLE();
86
87 return true;
88}
89
90bool Program::detachShader(Shader *shader)
91{
92 if (shader->getType() == GL_VERTEX_SHADER)
93 {
94 if (mVertexShader != shader)
95 {
96 return false;
97 }
98
99 mVertexShader->detach();
100 mVertexShader = NULL;
101 }
102 else if (shader->getType() == GL_FRAGMENT_SHADER)
103 {
104 if (mFragmentShader != shader)
105 {
106 return false;
107 }
108
109 mFragmentShader->detach();
110 mFragmentShader = NULL;
111 }
112 else UNREACHABLE();
113
114 unlink();
115
116 return true;
117}
118
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000119int Program::getAttachedShadersCount() const
120{
121 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
122}
123
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000124IDirect3DPixelShader9 *Program::getPixelShader()
125{
126 return mPixelExecutable;
127}
128
129IDirect3DVertexShader9 *Program::getVertexShader()
130{
131 return mVertexExecutable;
132}
133
134void Program::bindAttributeLocation(GLuint index, const char *name)
135{
136 if (index < MAX_VERTEX_ATTRIBS)
137 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000138 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
139 {
140 mAttributeBinding[i].erase(name);
141 }
142
143 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144 }
145}
146
147GLuint Program::getAttributeLocation(const char *name)
148{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000149 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000150 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000151 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000152 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000153 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000154 {
155 return index;
156 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000157 }
158 }
159
160 return -1;
161}
162
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000163int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164{
165 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
166 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000167 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000168 }
169
170 return -1;
171}
172
173// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
174// index referenced in the compiled HLSL shader
175GLint Program::getSamplerMapping(unsigned int samplerIndex)
176{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000177 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
178
179 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000180 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000181 return mSamplers[samplerIndex].logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182 }
183
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000184 return -1;
185}
186
187SamplerType Program::getSamplerType(unsigned int samplerIndex)
188{
189 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
190 assert(mSamplers[samplerIndex].active);
191
192 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000193}
194
195GLint Program::getUniformLocation(const char *name)
196{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000197 std::string nameStr(name);
198 int subscript = 0;
199 size_t beginB = nameStr.find('[');
200 size_t endB = nameStr.find(']');
201 if (beginB != std::string::npos && endB != std::string::npos)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000202 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000203 std::string subscrStr = nameStr.substr(beginB + 1, beginB - endB - 1);
204 nameStr.erase(beginB);
205 subscript = atoi(subscrStr.c_str());
206 }
207
208 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
209 {
210 if (mUniformIndex[location].name == decorate(nameStr) &&
211 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000212 {
213 return location;
214 }
215 }
216
217 return -1;
218}
219
220bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
221{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000222 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223 {
224 return false;
225 }
226
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000227 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
228
229 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000230 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000231 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000232
233 if (arraySize == 1 && count > 1)
234 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
235
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000236 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000237
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000238 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
239 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000240 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000241 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000242 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000243 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000244
245 if (arraySize == 1 && count > 1)
246 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000247
248 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000249 GLboolean *boolParams = new GLboolean[count];
250
251 for (int i = 0; i < count; ++i)
252 {
253 if (v[i] == 0.0f)
254 {
255 boolParams[i] = GL_FALSE;
256 }
257 else
258 {
259 boolParams[i] = GL_TRUE;
260 }
261 }
262
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000263 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
264 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000265
266 delete [] boolParams;
267 }
268 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000269 {
270 return false;
271 }
272
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000273 return true;
274}
275
276bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
277{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000278 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279 {
280 return false;
281 }
282
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000283 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
284
285 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000286 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000287 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000288
289 if (arraySize == 1 && count > 1)
290 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
291
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000292 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000293
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000294 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
295 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000296 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000297 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000298 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000299 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000300
301 if (arraySize == 1 && count > 1)
302 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
303
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000304 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
305
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000306 GLboolean *boolParams = new GLboolean[count * 2];
307
308 for (int i = 0; i < count * 2; ++i)
309 {
310 if (v[i] == 0.0f)
311 {
312 boolParams[i] = GL_FALSE;
313 }
314 else
315 {
316 boolParams[i] = GL_TRUE;
317 }
318 }
319
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000320 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
321 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000322
323 delete [] boolParams;
324 }
325 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000326 {
327 return false;
328 }
329
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330 return true;
331}
332
333bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
334{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000335 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000336 {
337 return false;
338 }
339
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000340 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
341
342 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000343 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000344 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000345
346 if (arraySize == 1 && count > 1)
347 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
348
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000349 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000350
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000351 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
352 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000353 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000354 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000355 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000356 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000357
358 if (arraySize == 1 && count > 1)
359 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
360
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000361 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000362 GLboolean *boolParams = new GLboolean[count * 3];
363
364 for (int i = 0; i < count * 3; ++i)
365 {
366 if (v[i] == 0.0f)
367 {
368 boolParams[i] = GL_FALSE;
369 }
370 else
371 {
372 boolParams[i] = GL_TRUE;
373 }
374 }
375
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000376 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
377 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000378
379 delete [] boolParams;
380 }
381 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000382 {
383 return false;
384 }
385
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000386 return true;
387}
388
389bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
390{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000391 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000392 {
393 return false;
394 }
395
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000396 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
397
398 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000399 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000400 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000401
402 if (arraySize == 1 && count > 1)
403 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
404
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000405 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000406
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000407 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
408 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000409 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000410 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000411 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000412 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000413
414 if (arraySize == 1 && count > 1)
415 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
416
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000417 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000418 GLboolean *boolParams = new GLboolean[count * 4];
419
420 for (int i = 0; i < count * 4; ++i)
421 {
422 if (v[i] == 0.0f)
423 {
424 boolParams[i] = GL_FALSE;
425 }
426 else
427 {
428 boolParams[i] = GL_TRUE;
429 }
430 }
431
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000432 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
433 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000434
435 delete [] boolParams;
436 }
437 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000438 {
439 return false;
440 }
441
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442 return true;
443}
444
445bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
446{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000447 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 {
449 return false;
450 }
451
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000452 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
453
454 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000455 {
456 return false;
457 }
458
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000459 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000460
461 if (arraySize == 1 && count > 1)
462 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
463
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000464 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000465
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000466 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
467 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000468
469 return true;
470}
471
472bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
473{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000474 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000475 {
476 return false;
477 }
478
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000479 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
480
481 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000482 {
483 return false;
484 }
485
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000486 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000487
488 if (arraySize == 1 && count > 1)
489 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
490
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000491 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000492
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000493 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
494 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000495
496 return true;
497}
498
499bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
500{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000501 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000502 {
503 return false;
504 }
505
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000506 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
507
508 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000509 {
510 return false;
511 }
512
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000513 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000514
515 if (arraySize == 1 && count > 1)
516 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
517
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000518 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000519
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000520 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
521 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000522
523 return true;
524}
525
526bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
527{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000528 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000529 {
530 return false;
531 }
532
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000533 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
534
535 if (targetUniform->type == GL_INT)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000536 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000537 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000538
539 if (arraySize == 1 && count > 1)
540 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
541
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000542 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000543
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000544 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
545 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000546 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000547 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000548 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000549 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000550
551 if (arraySize == 1 && count > 1)
552 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
553
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000554 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000555 GLboolean *boolParams = new GLboolean[count];
556
557 for (int i = 0; i < count; ++i)
558 {
559 if (v[i] == 0)
560 {
561 boolParams[i] = GL_FALSE;
562 }
563 else
564 {
565 boolParams[i] = GL_TRUE;
566 }
567 }
568
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000569 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
570 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000571
572 delete [] boolParams;
573 }
574 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000575 {
576 return false;
577 }
578
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000579 return true;
580}
581
582bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
583{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000584 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000585 {
586 return false;
587 }
588
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000589 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
590
591 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000592 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000593 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000594
595 if (arraySize == 1 && count > 1)
596 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
597
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000598 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000599
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000600 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
601 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000602 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000603 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000604 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000605 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000606
607 if (arraySize == 1 && count > 1)
608 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
609
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000610 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000611 GLboolean *boolParams = new GLboolean[count * 2];
612
613 for (int i = 0; i < count * 2; ++i)
614 {
615 if (v[i] == 0)
616 {
617 boolParams[i] = GL_FALSE;
618 }
619 else
620 {
621 boolParams[i] = GL_TRUE;
622 }
623 }
624
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000625 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
626 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000627
628 delete [] boolParams;
629 }
630 else
631 {
632 return false;
633 }
634
635 return true;
636}
637
638bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
639{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000640 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000641 {
642 return false;
643 }
644
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000645 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
646
647 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000648 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000649 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000650
651 if (arraySize == 1 && count > 1)
652 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
653
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000654 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000655
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000656 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
657 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000658 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000659 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000660 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000661 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000662
663 if (arraySize == 1 && count > 1)
664 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
665
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000666 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000667 GLboolean *boolParams = new GLboolean[count * 3];
668
669 for (int i = 0; i < count * 3; ++i)
670 {
671 if (v[i] == 0)
672 {
673 boolParams[i] = GL_FALSE;
674 }
675 else
676 {
677 boolParams[i] = GL_TRUE;
678 }
679 }
680
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000681 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
682 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000683
684 delete [] boolParams;
685 }
686 else
687 {
688 return false;
689 }
690
691 return true;
692}
693
694bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
695{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000696 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000697 {
698 return false;
699 }
700
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000701 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
702
703 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000704 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000705 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000706
707 if (arraySize == 1 && count > 1)
708 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
709
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000710 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000711
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000712 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
713 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000714 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000715 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000716 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000717 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000718
719 if (arraySize == 1 && count > 1)
720 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
721
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000722 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000723 GLboolean *boolParams = new GLboolean[count * 4];
724
725 for (int i = 0; i < count * 4; ++i)
726 {
727 if (v[i] == 0)
728 {
729 boolParams[i] = GL_FALSE;
730 }
731 else
732 {
733 boolParams[i] = GL_TRUE;
734 }
735 }
736
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000737 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
738 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000739
740 delete [] boolParams;
741 }
742 else
743 {
744 return false;
745 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000746
747 return true;
748}
749
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000750bool Program::getUniformfv(GLint location, GLfloat *params)
751{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000752 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000753 {
754 return false;
755 }
756
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000757 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000758
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000759 unsigned int count = UniformComponentCount(targetUniform->type);
760
761 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000762 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000763 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000764 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000765 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000766
767 for (unsigned int i = 0; i < count; ++i)
768 {
769 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
770 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000771 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000772 break;
773 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000774 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
775 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000776 break;
777 case GL_INT:
778 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000779 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000780
781 for (unsigned int i = 0; i < count; ++i)
782 {
783 params[i] = (float)intParams[i];
784 }
785 }
786 break;
787 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000788 }
789
790 return true;
791}
792
793bool Program::getUniformiv(GLint location, GLint *params)
794{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000795 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000796 {
797 return false;
798 }
799
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000800 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000801
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000802 unsigned int count = UniformComponentCount(targetUniform->type);
803
804 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000805 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000806 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000807 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000808 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000809
810 for (unsigned int i = 0; i < count; ++i)
811 {
812 params[i] = (GLint)boolParams[i];
813 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000814 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000815 break;
816 case GL_FLOAT:
817 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000818 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000819
820 for (unsigned int i = 0; i < count; ++i)
821 {
822 params[i] = (GLint)floatParams[i];
823 }
824 }
825 break;
826 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000827 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
828 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000829 break;
830 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000831 }
832
833 return true;
834}
835
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000836// Applies all the uniforms set for this program object to the Direct3D 9 device
837void Program::applyUniforms()
838{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000839 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000840 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000841 if (mUniformIndex[location].element != 0)
842 {
843 continue;
844 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000845
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000846 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
847
848 int arraySize = targetUniform->arraySize;
849 GLfloat *f = (GLfloat*)targetUniform->data;
850 GLint *i = (GLint*)targetUniform->data;
851 GLboolean *b = (GLboolean*)targetUniform->data;
852
853 switch (targetUniform->type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000854 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000855 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
856 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
857 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
858 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
859 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
860 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
861 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
862 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
863 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
864 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
865 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
866 case GL_INT: applyUniform1iv(location, arraySize, i); break;
867 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
868 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
869 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000870 default:
871 UNIMPLEMENTED(); // FIXME
872 UNREACHABLE();
873 }
874 }
875}
876
877// Compiles the HLSL code of the attached shaders into executable binaries
878ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
879{
880 if (!hlsl)
881 {
882 return NULL;
883 }
884
885 ID3DXBuffer *binary = NULL;
886 ID3DXBuffer *errorMessage = NULL;
887
daniel@transgaming.comcbbca002010-04-01 13:39:32 +0000888 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000889
890 if (SUCCEEDED(result))
891 {
892 return binary;
893 }
894
895 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
896 {
897 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
898 }
899
900 if (errorMessage)
901 {
902 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000903
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000904 TRACE("\n%s", hlsl);
905 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000906 }
907
908 return NULL;
909}
910
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000911void Program::parseVaryings(const char *structure, char *hlsl, VaryingArray &varyings)
912{
913 char *input = strstr(hlsl, structure);
914 input += strlen(structure);
915
916 while (input && *input != '}')
917 {
918 char varyingType[256];
919 char varyingName[256];
920 unsigned int semanticIndex;
921 int matches = sscanf(input, " %s %s : TEXCOORD%d;", varyingType, varyingName, &semanticIndex);
922
923 if (matches == 3)
924 {
925 ASSERT(semanticIndex <= 9); // Single character
926
927 varyings.push_back(Varying(varyingName, input));
928 }
929
930 input = strstr(input, ";");
931 input += 2;
932 }
933}
934
935bool Program::linkVaryings()
936{
937 if (!mPixelHLSL || !mVertexHLSL)
938 {
939 return false;
940 }
941
942 VaryingArray vertexVaryings;
943 VaryingArray pixelVaryings;
944
945 parseVaryings("struct VS_OUTPUT\n{\n", mVertexHLSL, vertexVaryings);
946 parseVaryings("struct PS_INPUT\n{\n", mPixelHLSL, pixelVaryings);
947
948 for (unsigned int out = 0; out < vertexVaryings.size(); out++)
949 {
950 unsigned int in;
951 for (in = 0; in < pixelVaryings.size(); in++)
952 {
953 if (vertexVaryings[out].name == pixelVaryings[in].name)
954 {
955 pixelVaryings[in].link = out;
956 vertexVaryings[out].link = in;
957
958 break;
959 }
960 }
961
962 if (in != pixelVaryings.size())
963 {
964 // FIXME: Verify matching type and qualifiers
965
966 char *outputSemantic = strstr(vertexVaryings[out].declaration, " : TEXCOORD");
967 char *inputSemantic = strstr(pixelVaryings[in].declaration, " : TEXCOORD");
968 outputSemantic[11] = inputSemantic[11];
969 }
970 else
971 {
972 // Comment out the declaration and output assignment
973 vertexVaryings[out].declaration[0] = '/';
974 vertexVaryings[out].declaration[1] = '/';
975
976 char outputString[256];
977 sprintf(outputString, " output.%s = ", vertexVaryings[out].name.c_str());
978 char *varyingOutput = strstr(mVertexHLSL, outputString);
979
980 varyingOutput[0] = '/';
981 varyingOutput[1] = '/';
982 }
983 }
984
985 // Verify that each pixel varying has been linked to a vertex varying
986 for (unsigned int in = 0; in < pixelVaryings.size(); in++)
987 {
988 if (pixelVaryings[in].link < 0)
989 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000990 appendToInfoLog("Pixel varying (%s) does not match any vertex varying", pixelVaryings[in].name);
991
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000992 return false;
993 }
994 }
995
996 return true;
997}
998
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000999// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1000// compiling them into binaries, determining the attribute mappings, and collecting
1001// a list of uniforms
1002void Program::link()
1003{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001004 unlink();
1005
1006 if (!mFragmentShader || !mFragmentShader->isCompiled())
1007 {
1008 return;
1009 }
1010
1011 if (!mVertexShader || !mVertexShader->isCompiled())
1012 {
1013 return;
1014 }
1015
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001016 Context *context = getContext();
1017 const char *vertexProfile = context->getVertexShaderProfile();
1018 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +00001019
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001020 const char *ps = mFragmentShader->getHLSL();
1021 const char *vs = mVertexShader->getHLSL();
1022
1023 mPixelHLSL = new char[strlen(ps) + 1];
1024 strcpy(mPixelHLSL, ps);
1025 mVertexHLSL = new char[strlen(vs) + 1];
1026 strcpy(mVertexHLSL, vs);
1027
1028 if (!linkVaryings())
1029 {
1030 return;
1031 }
1032
1033 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL, vertexProfile, &mConstantTableVS);
1034 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001035
1036 if (vertexBinary && pixelBinary)
1037 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001038 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001039 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1040 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1041
1042 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1043 {
1044 return error(GL_OUT_OF_MEMORY);
1045 }
1046
1047 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001048
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001049 vertexBinary->Release();
1050 pixelBinary->Release();
1051 vertexBinary = NULL;
1052 pixelBinary = NULL;
1053
1054 if (mVertexExecutable && mPixelExecutable)
1055 {
1056 if (!linkAttributes())
1057 {
1058 return;
1059 }
1060
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001061 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001062 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001063 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001064 }
1065
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001066 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001067 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001068 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001069 }
1070
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001071 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001072 }
1073 }
1074}
1075
1076// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1077bool Program::linkAttributes()
1078{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001079 unsigned int usedLocations = 0;
1080
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001081 // Link attributes that have a binding location
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001082 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1083 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001084 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1085 int location = getAttributeBinding(attribute.name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001086
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001087 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001088 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001089 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001090 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001091 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001092 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001093
daniel@transgaming.com85423182010-04-22 13:35:27 +00001094 mLinkedAttribute[location] = attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001095
1096 int size = AttributeVectorCount(attribute.type);
1097
1098 if (size + location > MAX_VERTEX_ATTRIBS)
1099 {
1100 appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
1101
1102 return false;
1103 }
1104
1105 for (int i = 0; i < size; i++)
1106 {
1107 usedLocations |= 1 << (location + i);
1108 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001109 }
1110 }
1111
1112 // Link attributes that don't have a binding location
1113 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS + 1; attributeIndex++)
1114 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001115 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1116 int location = getAttributeBinding(attribute.name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001117
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001118 if (!attribute.name.empty() && location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001119 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001120 int size = AttributeVectorCount(attribute.type);
1121 int availableIndex = AllocateFirstFreeBits(&usedLocations, size, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001122
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001123 if (availableIndex == -1 || availableIndex + size > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001124 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001125 appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001126
1127 return false; // Fail to link
1128 }
1129
daniel@transgaming.com85423182010-04-22 13:35:27 +00001130 mLinkedAttribute[availableIndex] = attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001131 }
1132 }
1133
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001134 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001135 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001136 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1137
1138 if (index == -1)
1139 {
1140 mSemanticIndex[attributeIndex++] = -1;
1141 }
1142 else
1143 {
1144 int size = AttributeVectorCount(mVertexShader->getAttribute(index).type);
1145
1146 for (int i = 0; i < size; i++)
1147 {
1148 mSemanticIndex[attributeIndex++] = index++;
1149 }
1150 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001151 }
1152
1153 return true;
1154}
1155
daniel@transgaming.com85423182010-04-22 13:35:27 +00001156int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001157{
1158 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1159 {
1160 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1161 {
1162 return location;
1163 }
1164 }
1165
1166 return -1;
1167}
1168
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001169bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1170{
1171 D3DXCONSTANTTABLE_DESC constantTableDescription;
1172 D3DXCONSTANT_DESC constantDescription;
1173 UINT descriptionCount = 1;
1174
1175 constantTable->GetDesc(&constantTableDescription);
1176
1177 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1178 {
1179 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1180 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1181
1182 if (!defineUniform(constantHandle, constantDescription))
1183 {
1184 return false;
1185 }
1186 }
1187
1188 return true;
1189}
1190
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001191// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001192// Returns true if succesful (uniform not already defined)
1193bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1194{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001195 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1196 {
1197 unsigned int samplerIndex = constantDescription.RegisterIndex;
1198
1199 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1200
1201 mSamplers[samplerIndex].active = true;
1202 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1203 mSamplers[samplerIndex].logicalTextureUnit = 0;
1204 }
1205
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001206 switch(constantDescription.Class)
1207 {
1208 case D3DXPC_STRUCT:
1209 {
1210 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1211 {
1212 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1213
1214 D3DXCONSTANT_DESC fieldDescription;
1215 UINT descriptionCount = 1;
1216
1217 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1218
1219 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1220 {
1221 return false;
1222 }
1223 }
1224
1225 return true;
1226 }
1227 case D3DXPC_SCALAR:
1228 case D3DXPC_VECTOR:
1229 case D3DXPC_MATRIX_COLUMNS:
1230 case D3DXPC_OBJECT:
1231 return defineUniform(constantDescription, name + constantDescription.Name);
1232 default:
1233 UNREACHABLE();
1234 return false;
1235 }
1236}
1237
1238bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1239{
1240 Uniform *uniform = createUniform(constantDescription, name);
1241
1242 if(!uniform)
1243 {
1244 return false;
1245 }
1246
1247 // Check if already defined
1248 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001249 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001250
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001251 if (location >= 0)
1252 {
1253 delete uniform;
1254
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001255 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001256 {
1257 return false;
1258 }
1259 else
1260 {
1261 return true;
1262 }
1263 }
1264
1265 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001266 unsigned int uniformIndex = mUniforms.size() - 1;
1267
1268 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1269 {
1270 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1271 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001272
1273 return true;
1274}
1275
1276Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001277{
1278 if (constantDescription.Rows == 1) // Vectors and scalars
1279 {
1280 switch (constantDescription.Type)
1281 {
1282 case D3DXPT_SAMPLER2D:
1283 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001284 switch (constantDescription.Columns)
1285 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001286 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001287 default: UNREACHABLE();
1288 }
1289 break;
1290 case D3DXPT_BOOL:
1291 switch (constantDescription.Columns)
1292 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001293 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1294 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1295 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1296 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001297 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001298 }
1299 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001300 case D3DXPT_INT:
1301 switch (constantDescription.Columns)
1302 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001303 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1304 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1305 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1306 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001307 default: UNREACHABLE();
1308 }
1309 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001310 case D3DXPT_FLOAT:
1311 switch (constantDescription.Columns)
1312 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001313 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1314 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1315 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1316 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001317 default: UNREACHABLE();
1318 }
1319 break;
1320 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001321 UNREACHABLE();
1322 }
1323 }
1324 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1325 {
1326 switch (constantDescription.Type)
1327 {
1328 case D3DXPT_FLOAT:
1329 switch (constantDescription.Rows)
1330 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001331 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1332 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1333 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001334 default: UNREACHABLE();
1335 }
1336 break;
1337 default: UNREACHABLE();
1338 }
1339 }
1340 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001341
1342 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001343}
1344
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001345// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001346std::string Program::decorate(const std::string &string)
1347{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001348 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001349 {
1350 return "_" + string;
1351 }
1352 else
1353 {
1354 return string;
1355 }
1356}
1357
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001358std::string Program::undecorate(const std::string &string)
1359{
1360 if (string.substr(0, 1) == "_")
1361 {
1362 return string.substr(1);
1363 }
1364 else
1365 {
1366 return string;
1367 }
1368}
1369
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001370bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1371{
1372 BOOL *vector = new BOOL[count];
1373 for (int i = 0; i < count; i++)
1374 {
1375 if (v[i] == GL_FALSE)
1376 vector[i] = 0;
1377 else
1378 vector[i] = 1;
1379 }
1380
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001381 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1382
1383 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1384 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001385 IDirect3DDevice9 *device = getDevice();
1386
1387 if (constantPS)
1388 {
1389 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1390 }
1391
1392 if (constantVS)
1393 {
1394 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1395 }
1396
1397 delete [] vector;
1398
1399 return true;
1400}
1401
1402bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1403{
1404 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1405
1406 for (int i = 0; i < count; i++)
1407 {
1408 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1409 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1410
1411 v += 2;
1412 }
1413
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001414 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1415
1416 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1417 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001418 IDirect3DDevice9 *device = getDevice();
1419
1420 if (constantPS)
1421 {
1422 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1423 }
1424
1425 if (constantVS)
1426 {
1427 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1428 }
1429
1430 delete[] vector;
1431
1432 return true;
1433}
1434
1435bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1436{
1437 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1438
1439 for (int i = 0; i < count; i++)
1440 {
1441 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1442 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1443 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1444
1445 v += 3;
1446 }
1447
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001448 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1449
1450 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1451 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001452 IDirect3DDevice9 *device = getDevice();
1453
1454 if (constantPS)
1455 {
1456 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1457 }
1458
1459 if (constantVS)
1460 {
1461 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1462 }
1463
1464 delete[] vector;
1465
1466 return true;
1467}
1468
1469bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1470{
1471 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1472
1473 for (int i = 0; i < count; i++)
1474 {
1475 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1476 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1477 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1478 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1479
1480 v += 3;
1481 }
1482
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001483 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1484
1485 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1486 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001487 IDirect3DDevice9 *device = getDevice();
1488
1489 if (constantPS)
1490 {
1491 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1492 }
1493
1494 if (constantVS)
1495 {
1496 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1497 }
1498
1499 delete [] vector;
1500
1501 return true;
1502}
1503
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001504bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1505{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001506 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1507
1508 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1509 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001510 IDirect3DDevice9 *device = getDevice();
1511
1512 if (constantPS)
1513 {
1514 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1515 }
1516
1517 if (constantVS)
1518 {
1519 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1520 }
1521
1522 return true;
1523}
1524
1525bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1526{
1527 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1528
1529 for (int i = 0; i < count; i++)
1530 {
1531 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1532
1533 v += 2;
1534 }
1535
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001536 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1537
1538 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1539 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001540 IDirect3DDevice9 *device = getDevice();
1541
1542 if (constantPS)
1543 {
1544 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1545 }
1546
1547 if (constantVS)
1548 {
1549 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1550 }
1551
1552 delete[] vector;
1553
1554 return true;
1555}
1556
1557bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1558{
1559 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1560
1561 for (int i = 0; i < count; i++)
1562 {
1563 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1564
1565 v += 3;
1566 }
1567
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001568 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1569
1570 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1571 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001572 IDirect3DDevice9 *device = getDevice();
1573
1574 if (constantPS)
1575 {
1576 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1577 }
1578
1579 if (constantVS)
1580 {
1581 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1582 }
1583
1584 delete[] vector;
1585
1586 return true;
1587}
1588
1589bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1590{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001591 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1592
1593 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1594 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001595 IDirect3DDevice9 *device = getDevice();
1596
1597 if (constantPS)
1598 {
1599 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
1600 }
1601
1602 if (constantVS)
1603 {
1604 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
1605 }
1606
1607 return true;
1608}
1609
1610bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
1611{
1612 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1613
1614 for (int i = 0; i < count; i++)
1615 {
1616 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
1617 value[1], value[3], 0, 0,
1618 0, 0, 1, 0,
1619 0, 0, 0, 1);
1620
1621 value += 4;
1622 }
1623
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001624 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1625
1626 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1627 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001628 IDirect3DDevice9 *device = getDevice();
1629
1630 if (constantPS)
1631 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001632 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001633 }
1634
1635 if (constantVS)
1636 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001637 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001638 }
1639
1640 delete[] matrix;
1641
1642 return true;
1643}
1644
1645bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
1646{
1647 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1648
1649 for (int i = 0; i < count; i++)
1650 {
1651 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
1652 value[1], value[4], value[7], 0,
1653 value[2], value[5], value[8], 0,
1654 0, 0, 0, 1);
1655
1656 value += 9;
1657 }
1658
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001659 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1660
1661 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1662 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001663 IDirect3DDevice9 *device = getDevice();
1664
1665 if (constantPS)
1666 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001667 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001668 }
1669
1670 if (constantVS)
1671 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001672 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001673 }
1674
1675 delete[] matrix;
1676
1677 return true;
1678}
1679
1680bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
1681{
1682 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1683
1684 for (int i = 0; i < count; i++)
1685 {
1686 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
1687 value[1], value[5], value[9], value[13],
1688 value[2], value[6], value[10], value[14],
1689 value[3], value[7], value[11], value[15]);
1690
1691 value += 16;
1692 }
1693
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001694 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1695
1696 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1697 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001698 IDirect3DDevice9 *device = getDevice();
1699
1700 if (constantPS)
1701 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001702 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001703 }
1704
1705 if (constantVS)
1706 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001707 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001708 }
1709
1710 delete[] matrix;
1711
1712 return true;
1713}
1714
1715bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
1716{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001717 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1718
1719 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1720 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001721 IDirect3DDevice9 *device = getDevice();
1722
1723 if (constantPS)
1724 {
1725 D3DXCONSTANT_DESC constantDescription;
1726 UINT descriptionCount = 1;
1727 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
1728
daniel@transgaming.com2884b782010-03-08 21:30:48 +00001729 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001730 {
1731 return false;
1732 }
1733
1734 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1735 {
1736 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
1737
1738 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
1739 {
1740 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001741
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001742 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
1743 {
1744 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1745 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001746 ASSERT(mSamplers[samplerIndex].active);
1747 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001748 }
1749 }
1750 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001751
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001752 return true;
1753 }
1754 }
1755
1756 if (constantPS)
1757 {
1758 mConstantTablePS->SetIntArray(device, constantPS, v, count);
1759 }
1760
1761 if (constantVS)
1762 {
1763 mConstantTableVS->SetIntArray(device, constantVS, v, count);
1764 }
1765
1766 return true;
1767}
1768
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001769bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
1770{
1771 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1772
1773 for (int i = 0; i < count; i++)
1774 {
1775 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
1776
1777 v += 2;
1778 }
1779
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001780 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1781
1782 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1783 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001784 IDirect3DDevice9 *device = getDevice();
1785
1786 if (constantPS)
1787 {
1788 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1789 }
1790
1791 if (constantVS)
1792 {
1793 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1794 }
1795
1796 delete[] vector;
1797
1798 return true;
1799}
1800
1801bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
1802{
1803 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1804
1805 for (int i = 0; i < count; i++)
1806 {
1807 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
1808
1809 v += 3;
1810 }
1811
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001812 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1813
1814 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1815 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001816 IDirect3DDevice9 *device = getDevice();
1817
1818 if (constantPS)
1819 {
1820 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1821 }
1822
1823 if (constantVS)
1824 {
1825 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1826 }
1827
1828 delete[] vector;
1829
1830 return true;
1831}
1832
1833bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
1834{
1835 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1836
1837 for (int i = 0; i < count; i++)
1838 {
1839 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
1840
1841 v += 4;
1842 }
1843
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001844 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1845
1846 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1847 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001848 IDirect3DDevice9 *device = getDevice();
1849
1850 if (constantPS)
1851 {
1852 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1853 }
1854
1855 if (constantVS)
1856 {
1857 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1858 }
1859
1860 delete [] vector;
1861
1862 return true;
1863}
1864
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001865void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001866{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001867 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001868 {
1869 return;
1870 }
1871
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001872 char info[1024];
1873
1874 va_list vararg;
1875 va_start(vararg, format);
1876 vsnprintf(info, sizeof(info), format, vararg);
1877 va_end(vararg);
1878
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001879 size_t infoLength = strlen(info);
1880
1881 if (!mInfoLog)
1882 {
1883 mInfoLog = new char[infoLength + 1];
1884 strcpy(mInfoLog, info);
1885 }
1886 else
1887 {
1888 size_t logLength = strlen(mInfoLog);
1889 char *newLog = new char[logLength + infoLength + 1];
1890 strcpy(newLog, mInfoLog);
1891 strcpy(newLog + logLength, info);
1892
1893 delete[] mInfoLog;
1894 mInfoLog = newLog;
1895 }
1896}
1897
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001898void Program::resetInfoLog()
1899{
1900 if (mInfoLog)
1901 {
1902 delete [] mInfoLog;
1903 }
1904}
1905
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001906// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
1907void Program::unlink(bool destroy)
1908{
1909 if (destroy) // Object being destructed
1910 {
1911 if (mFragmentShader)
1912 {
1913 mFragmentShader->detach();
1914 mFragmentShader = NULL;
1915 }
1916
1917 if (mVertexShader)
1918 {
1919 mVertexShader->detach();
1920 mVertexShader = NULL;
1921 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001922 }
1923
1924 if (mPixelExecutable)
1925 {
1926 mPixelExecutable->Release();
1927 mPixelExecutable = NULL;
1928 }
1929
1930 if (mVertexExecutable)
1931 {
1932 mVertexExecutable->Release();
1933 mVertexExecutable = NULL;
1934 }
1935
1936 if (mConstantTablePS)
1937 {
1938 mConstantTablePS->Release();
1939 mConstantTablePS = NULL;
1940 }
1941
1942 if (mConstantTableVS)
1943 {
1944 mConstantTableVS->Release();
1945 mConstantTableVS = NULL;
1946 }
1947
1948 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1949 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001950 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001951 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001952 }
1953
1954 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
1955 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001956 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001957 }
1958
1959 while (!mUniforms.empty())
1960 {
1961 delete mUniforms.back();
1962 mUniforms.pop_back();
1963 }
1964
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001965 mUniformIndex.clear();
1966
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001967 delete[] mPixelHLSL;
1968 mPixelHLSL = NULL;
1969
1970 delete[] mVertexHLSL;
1971 mVertexHLSL = NULL;
1972
1973 delete[] mInfoLog;
1974 mInfoLog = NULL;
1975
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001976 mLinked = false;
1977}
1978
1979bool Program::isLinked()
1980{
1981 return mLinked;
1982}
1983
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001984bool Program::isValidated() const
1985{
1986 return mValidated;
1987}
1988
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001989int Program::getInfoLogLength() const
1990{
1991 if (!mInfoLog)
1992 {
1993 return 0;
1994 }
1995 else
1996 {
1997 return strlen(mInfoLog) + 1;
1998 }
1999}
2000
2001void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2002{
2003 int index = 0;
2004
2005 if (mInfoLog)
2006 {
2007 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2008 {
2009 infoLog[index] = mInfoLog[index];
2010 index++;
2011 }
2012 }
2013
2014 if (bufSize)
2015 {
2016 infoLog[index] = '\0';
2017 }
2018
2019 if (length)
2020 {
2021 *length = index;
2022 }
2023}
2024
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002025void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2026{
2027 int total = 0;
2028
2029 if (mVertexShader)
2030 {
2031 if (total < maxCount)
2032 {
2033 shaders[total] = mVertexShader->getHandle();
2034 }
2035
2036 total++;
2037 }
2038
2039 if (mFragmentShader)
2040 {
2041 if (total < maxCount)
2042 {
2043 shaders[total] = mFragmentShader->getHandle();
2044 }
2045
2046 total++;
2047 }
2048
2049 if (count)
2050 {
2051 *count = total;
2052 }
2053}
2054
daniel@transgaming.com85423182010-04-22 13:35:27 +00002055void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2056{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002057 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002058 for (unsigned int i = 0; i < index; i++)
2059 {
2060 do
2061 {
2062 attribute++;
2063
2064 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2065 }
2066 while (mLinkedAttribute[attribute].name.empty());
2067 }
2068
2069 if (bufsize > 0)
2070 {
2071 const char *string = mLinkedAttribute[attribute].name.c_str();
2072
2073 strncpy(name, string, bufsize);
2074 name[bufsize - 1] = '\0';
2075
2076 if (length)
2077 {
2078 *length = strlen(name);
2079 }
2080 }
2081
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002082 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002083
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002084 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002085}
2086
2087GLint Program::getActiveAttributeCount()
2088{
2089 int count = 0;
2090
2091 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2092 {
2093 if (!mLinkedAttribute[attributeIndex].name.empty())
2094 {
2095 count++;
2096 }
2097 }
2098
2099 return count;
2100}
2101
2102GLint Program::getActiveAttributeMaxLength()
2103{
2104 int maxLength = 0;
2105
2106 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2107 {
2108 if (!mLinkedAttribute[attributeIndex].name.empty())
2109 {
2110 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2111 }
2112 }
2113
2114 return maxLength;
2115}
2116
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002117void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2118{
2119 unsigned int uniform = 0;
2120 for (unsigned int i = 0; i < index; i++)
2121 {
2122 do
2123 {
2124 uniform++;
2125
2126 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2127 }
2128 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2129 }
2130
2131 if (bufsize > 0)
2132 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002133 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002134
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002135 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002136 name[bufsize - 1] = '\0';
2137
2138 if (length)
2139 {
2140 *length = strlen(name);
2141 }
2142 }
2143
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002144 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002145
2146 *type = mUniforms[uniform]->type;
2147}
2148
2149GLint Program::getActiveUniformCount()
2150{
2151 int count = 0;
2152
2153 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2154 {
2155 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2156 {
2157 count++;
2158 }
2159 }
2160
2161 return count;
2162}
2163
2164GLint Program::getActiveUniformMaxLength()
2165{
2166 int maxLength = 0;
2167
2168 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2169 {
2170 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2171 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002172 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002173 }
2174 }
2175
2176 return maxLength;
2177}
2178
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002179void Program::flagForDeletion()
2180{
2181 mDeleteStatus = true;
2182}
2183
2184bool Program::isFlaggedForDeletion() const
2185{
2186 return mDeleteStatus;
2187}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002188
2189void Program::validate()
2190{
2191 resetInfoLog();
2192
2193 if (!isLinked())
2194 {
2195 appendToInfoLog("Program has not been successfully linked.");
2196 mValidated = false;
2197 }
2198 else if (!validateSamplers())
2199 {
2200 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2201 mValidated = false;
2202 }
2203 else
2204 {
2205 mValidated = true;
2206 }
2207}
2208
2209bool Program::validateSamplers() const
2210{
2211 // if any two active samplers in a program are of different types, but refer to the same
2212 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2213 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2214 std::map<int, SamplerType> samplerMap;
2215 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2216 {
2217 if (mSamplers[i].active)
2218 {
2219 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2220 {
2221 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2222 return false;
2223 }
2224 else
2225 {
2226 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2227 }
2228 }
2229 }
2230
2231 return true;
2232}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002233}