blob: 614d2acf03edb68d7d5f9a6698fd42d159d3dbf0 [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.com4fa08332010-05-11 02:29:27 +000020unsigned int Program::mCurrentSerial = 1;
21
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000022Uniform::Uniform(GLenum type, const std::string &name, unsigned int arraySize) : type(type), name(name), arraySize(arraySize)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000023{
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000024 int bytes = UniformTypeSize(type) * arraySize;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000025 data = new unsigned char[bytes];
26 memset(data, 0, bytes);
27 dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000028}
29
30Uniform::~Uniform()
31{
32 delete[] data;
33}
34
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +000035UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
36 : name(name), element(element), index(index)
37{
38}
39
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000040Program::Program()
41{
42 mFragmentShader = NULL;
43 mVertexShader = NULL;
44
45 mPixelExecutable = NULL;
46 mVertexExecutable = NULL;
47 mConstantTablePS = NULL;
48 mConstantTableVS = NULL;
49
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +000050 mPixelHLSL = NULL;
51 mVertexHLSL = NULL;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000052 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +000053 mValidated = false;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000054
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000055 unlink();
56
57 mDeleteStatus = false;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000058
59 mSerial = issueSerial();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000060}
61
62Program::~Program()
63{
64 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000065
66 if (mVertexShader != NULL)
67 {
68 mVertexShader->detach();
69 }
70
71 if (mFragmentShader != NULL)
72 {
73 mFragmentShader->detach();
74 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000075}
76
77bool Program::attachShader(Shader *shader)
78{
79 if (shader->getType() == GL_VERTEX_SHADER)
80 {
81 if (mVertexShader)
82 {
83 return false;
84 }
85
86 mVertexShader = (VertexShader*)shader;
87 mVertexShader->attach();
88 }
89 else if (shader->getType() == GL_FRAGMENT_SHADER)
90 {
91 if (mFragmentShader)
92 {
93 return false;
94 }
95
96 mFragmentShader = (FragmentShader*)shader;
97 mFragmentShader->attach();
98 }
99 else UNREACHABLE();
100
101 return true;
102}
103
104bool Program::detachShader(Shader *shader)
105{
106 if (shader->getType() == GL_VERTEX_SHADER)
107 {
108 if (mVertexShader != shader)
109 {
110 return false;
111 }
112
113 mVertexShader->detach();
114 mVertexShader = NULL;
115 }
116 else if (shader->getType() == GL_FRAGMENT_SHADER)
117 {
118 if (mFragmentShader != shader)
119 {
120 return false;
121 }
122
123 mFragmentShader->detach();
124 mFragmentShader = NULL;
125 }
126 else UNREACHABLE();
127
128 unlink();
129
130 return true;
131}
132
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000133int Program::getAttachedShadersCount() const
134{
135 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
136}
137
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138IDirect3DPixelShader9 *Program::getPixelShader()
139{
140 return mPixelExecutable;
141}
142
143IDirect3DVertexShader9 *Program::getVertexShader()
144{
145 return mVertexExecutable;
146}
147
148void Program::bindAttributeLocation(GLuint index, const char *name)
149{
150 if (index < MAX_VERTEX_ATTRIBS)
151 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000152 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
153 {
154 mAttributeBinding[i].erase(name);
155 }
156
157 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000158 }
159}
160
161GLuint Program::getAttributeLocation(const char *name)
162{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000163 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000165 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000166 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000167 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000168 {
169 return index;
170 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171 }
172 }
173
174 return -1;
175}
176
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000177int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000178{
179 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
180 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000181 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182 }
183
184 return -1;
185}
186
187// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
188// index referenced in the compiled HLSL shader
189GLint Program::getSamplerMapping(unsigned int samplerIndex)
190{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000191 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
192
193 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000194 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000195 return mSamplers[samplerIndex].logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196 }
197
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000198 return -1;
199}
200
201SamplerType Program::getSamplerType(unsigned int samplerIndex)
202{
203 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
204 assert(mSamplers[samplerIndex].active);
205
206 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207}
208
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000209bool Program::isSamplerDirty(unsigned int samplerIndex) const
210{
211 if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]))
212 {
213 return mSamplers[samplerIndex].dirty;
214 }
215 else UNREACHABLE();
216
217 return false;
218}
219
220void Program::setSamplerDirty(unsigned int samplerIndex, bool dirty)
221{
222 if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]))
223 {
224 mSamplers[samplerIndex].dirty = dirty;
225 }
226 else UNREACHABLE();
227}
228
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000229GLint Program::getUniformLocation(const char *name)
230{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000231 std::string nameStr(name);
232 int subscript = 0;
233 size_t beginB = nameStr.find('[');
234 size_t endB = nameStr.find(']');
235 if (beginB != std::string::npos && endB != std::string::npos)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000236 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000237 std::string subscrStr = nameStr.substr(beginB + 1, beginB - endB - 1);
238 nameStr.erase(beginB);
239 subscript = atoi(subscrStr.c_str());
240 }
241
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000242 nameStr = decorate(nameStr);
243
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000244 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
245 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000246 if (mUniformIndex[location].name == nameStr &&
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000247 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000248 {
249 return location;
250 }
251 }
252
253 return -1;
254}
255
256bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
257{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000258 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259 {
260 return false;
261 }
262
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000263 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000264 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000265
266 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000267 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000268 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000269
270 if (arraySize == 1 && count > 1)
271 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
272
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000273 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000274
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000275 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
276 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000277 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000278 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000279 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000280 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000281
282 if (arraySize == 1 && count > 1)
283 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000284
285 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000286 GLboolean *boolParams = new GLboolean[count];
287
288 for (int i = 0; i < count; ++i)
289 {
290 if (v[i] == 0.0f)
291 {
292 boolParams[i] = GL_FALSE;
293 }
294 else
295 {
296 boolParams[i] = GL_TRUE;
297 }
298 }
299
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000300 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
301 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000302
303 delete [] boolParams;
304 }
305 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000306 {
307 return false;
308 }
309
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000310 return true;
311}
312
313bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
314{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000315 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000316 {
317 return false;
318 }
319
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000320 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000321 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000322
323 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000324 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000325 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000326
327 if (arraySize == 1 && count > 1)
328 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
329
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000330 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000331
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000332 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
333 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000334 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000335 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000336 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000337 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000338
339 if (arraySize == 1 && count > 1)
340 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
341
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000342 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
343
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000344 GLboolean *boolParams = new GLboolean[count * 2];
345
346 for (int i = 0; i < count * 2; ++i)
347 {
348 if (v[i] == 0.0f)
349 {
350 boolParams[i] = GL_FALSE;
351 }
352 else
353 {
354 boolParams[i] = GL_TRUE;
355 }
356 }
357
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000358 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
359 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000360
361 delete [] boolParams;
362 }
363 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000364 {
365 return false;
366 }
367
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000368 return true;
369}
370
371bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
372{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000373 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000374 {
375 return false;
376 }
377
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000378 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000379 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000380
381 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000382 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000383 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000384
385 if (arraySize == 1 && count > 1)
386 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
387
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000388 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000389
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000390 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
391 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000392 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000393 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000394 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000395 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000396
397 if (arraySize == 1 && count > 1)
398 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
399
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000400 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000401 GLboolean *boolParams = new GLboolean[count * 3];
402
403 for (int i = 0; i < count * 3; ++i)
404 {
405 if (v[i] == 0.0f)
406 {
407 boolParams[i] = GL_FALSE;
408 }
409 else
410 {
411 boolParams[i] = GL_TRUE;
412 }
413 }
414
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000415 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
416 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000417
418 delete [] boolParams;
419 }
420 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000421 {
422 return false;
423 }
424
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000425 return true;
426}
427
428bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
429{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000430 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000431 {
432 return false;
433 }
434
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000435 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000436 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000437
438 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000439 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000440 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000441
442 if (arraySize == 1 && count > 1)
443 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
444
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000445 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000446
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000447 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
448 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000449 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000450 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000451 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000452 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000453
454 if (arraySize == 1 && count > 1)
455 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
456
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000457 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000458 GLboolean *boolParams = new GLboolean[count * 4];
459
460 for (int i = 0; i < count * 4; ++i)
461 {
462 if (v[i] == 0.0f)
463 {
464 boolParams[i] = GL_FALSE;
465 }
466 else
467 {
468 boolParams[i] = GL_TRUE;
469 }
470 }
471
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000472 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
473 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000474
475 delete [] boolParams;
476 }
477 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000478 {
479 return false;
480 }
481
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000482 return true;
483}
484
485bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
486{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000487 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000488 {
489 return false;
490 }
491
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000492 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000493 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000494
495 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000496 {
497 return false;
498 }
499
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000500 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000501
502 if (arraySize == 1 && count > 1)
503 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
504
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000505 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000506
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000507 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
508 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000509
510 return true;
511}
512
513bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
514{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000515 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000516 {
517 return false;
518 }
519
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000520 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000521 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000522
523 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000524 {
525 return false;
526 }
527
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000528 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000529
530 if (arraySize == 1 && count > 1)
531 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
532
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000533 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000534
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000535 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
536 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000537
538 return true;
539}
540
541bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
542{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000543 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000544 {
545 return false;
546 }
547
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000548 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000549 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000550
551 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000552 {
553 return false;
554 }
555
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000556 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000557
558 if (arraySize == 1 && count > 1)
559 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
560
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000561 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000562
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000563 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
564 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000565
566 return true;
567}
568
569bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
570{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000571 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000572 {
573 return false;
574 }
575
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000576 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000577 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000578
579 if (targetUniform->type == GL_INT)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000580 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000581 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000582
583 if (arraySize == 1 && count > 1)
584 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
585
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000586 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000587
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000588 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
589 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000590 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000591 else if (targetUniform->type == GL_BOOL)
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 GLboolean *boolParams = new GLboolean[count];
600
601 for (int i = 0; i < count; ++i)
602 {
603 if (v[i] == 0)
604 {
605 boolParams[i] = GL_FALSE;
606 }
607 else
608 {
609 boolParams[i] = GL_TRUE;
610 }
611 }
612
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000613 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
614 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000615
616 delete [] boolParams;
617 }
618 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000619 {
620 return false;
621 }
622
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000623 return true;
624}
625
626bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
627{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000628 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000629 {
630 return false;
631 }
632
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000633 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000634 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000635
636 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000637 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000638 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000639
640 if (arraySize == 1 && count > 1)
641 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
642
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000643 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000644
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000645 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
646 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000647 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000648 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000649 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000650 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000651
652 if (arraySize == 1 && count > 1)
653 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
654
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000655 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000656 GLboolean *boolParams = new GLboolean[count * 2];
657
658 for (int i = 0; i < count * 2; ++i)
659 {
660 if (v[i] == 0)
661 {
662 boolParams[i] = GL_FALSE;
663 }
664 else
665 {
666 boolParams[i] = GL_TRUE;
667 }
668 }
669
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000670 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
671 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000672
673 delete [] boolParams;
674 }
675 else
676 {
677 return false;
678 }
679
680 return true;
681}
682
683bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
684{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000685 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000686 {
687 return false;
688 }
689
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000690 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000691 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000692
693 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000694 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000695 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000696
697 if (arraySize == 1 && count > 1)
698 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
699
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000700 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000701
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000702 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
703 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000704 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000705 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000706 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000707 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000708
709 if (arraySize == 1 && count > 1)
710 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
711
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000712 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000713 GLboolean *boolParams = new GLboolean[count * 3];
714
715 for (int i = 0; i < count * 3; ++i)
716 {
717 if (v[i] == 0)
718 {
719 boolParams[i] = GL_FALSE;
720 }
721 else
722 {
723 boolParams[i] = GL_TRUE;
724 }
725 }
726
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000727 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
728 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000729
730 delete [] boolParams;
731 }
732 else
733 {
734 return false;
735 }
736
737 return true;
738}
739
740bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
741{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000742 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000743 {
744 return false;
745 }
746
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000747 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000748 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000749
750 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000751 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000752 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000753
754 if (arraySize == 1 && count > 1)
755 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
756
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000757 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000758
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000759 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
760 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000761 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000762 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000763 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000764 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000765
766 if (arraySize == 1 && count > 1)
767 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
768
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000769 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000770 GLboolean *boolParams = new GLboolean[count * 4];
771
772 for (int i = 0; i < count * 4; ++i)
773 {
774 if (v[i] == 0)
775 {
776 boolParams[i] = GL_FALSE;
777 }
778 else
779 {
780 boolParams[i] = GL_TRUE;
781 }
782 }
783
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000784 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
785 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000786
787 delete [] boolParams;
788 }
789 else
790 {
791 return false;
792 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000793
794 return true;
795}
796
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000797bool Program::getUniformfv(GLint location, GLfloat *params)
798{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000799 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000800 {
801 return false;
802 }
803
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000804 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000805
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000806 unsigned int count = UniformComponentCount(targetUniform->type);
807
808 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000809 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000810 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000811 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000812 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000813
814 for (unsigned int i = 0; i < count; ++i)
815 {
816 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
817 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000818 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000819 break;
820 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000821 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
822 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000823 break;
824 case GL_INT:
825 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000826 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000827
828 for (unsigned int i = 0; i < count; ++i)
829 {
830 params[i] = (float)intParams[i];
831 }
832 }
833 break;
834 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000835 }
836
837 return true;
838}
839
840bool Program::getUniformiv(GLint location, GLint *params)
841{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000842 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000843 {
844 return false;
845 }
846
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000847 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000848
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000849 unsigned int count = UniformComponentCount(targetUniform->type);
850
851 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000852 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000853 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000854 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000855 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000856
857 for (unsigned int i = 0; i < count; ++i)
858 {
859 params[i] = (GLint)boolParams[i];
860 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000861 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000862 break;
863 case GL_FLOAT:
864 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000865 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000866
867 for (unsigned int i = 0; i < count; ++i)
868 {
869 params[i] = (GLint)floatParams[i];
870 }
871 }
872 break;
873 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000874 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
875 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000876 break;
877 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000878 }
879
880 return true;
881}
882
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000883void Program::dirtyAllUniforms()
884{
885 for (unsigned int index = 0; index < mUniforms.size(); index++)
886 {
887 mUniforms[index]->dirty = true;
888 }
889}
890
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000891void Program::dirtyAllSamplers()
892{
893 for (unsigned int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; ++index)
894 {
895 mSamplers[index].dirty = true;
896 }
897}
898
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000899// Applies all the uniforms set for this program object to the Direct3D 9 device
900void Program::applyUniforms()
901{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000902 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000903 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000904 if (mUniformIndex[location].element != 0)
905 {
906 continue;
907 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000908
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000909 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
910
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000911 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000912 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000913 int arraySize = targetUniform->arraySize;
914 GLfloat *f = (GLfloat*)targetUniform->data;
915 GLint *i = (GLint*)targetUniform->data;
916 GLboolean *b = (GLboolean*)targetUniform->data;
917
918 switch (targetUniform->type)
919 {
920 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
921 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
922 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
923 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
924 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
925 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
926 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
927 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
928 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
929 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
930 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
931 case GL_INT: applyUniform1iv(location, arraySize, i); break;
932 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
933 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
934 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
935 default:
936 UNREACHABLE();
937 }
938
939 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000940 }
941 }
942}
943
944// Compiles the HLSL code of the attached shaders into executable binaries
945ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
946{
947 if (!hlsl)
948 {
949 return NULL;
950 }
951
952 ID3DXBuffer *binary = NULL;
953 ID3DXBuffer *errorMessage = NULL;
954
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000955 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, NULL, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000956
957 if (SUCCEEDED(result))
958 {
959 return binary;
960 }
961
962 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
963 {
964 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
965 }
966
967 if (errorMessage)
968 {
969 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000970
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000971 TRACE("\n%s", hlsl);
972 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000973 }
974
975 return NULL;
976}
977
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000978void Program::parseVaryings(const char *structure, char *hlsl, VaryingArray &varyings)
979{
980 char *input = strstr(hlsl, structure);
981 input += strlen(structure);
982
983 while (input && *input != '}')
984 {
985 char varyingType[256];
986 char varyingName[256];
987 unsigned int semanticIndex;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000988
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000989 int matches = sscanf(input, " %s %s : TEXCOORD%d;", varyingType, varyingName, &semanticIndex);
990
991 if (matches == 3)
992 {
993 ASSERT(semanticIndex <= 9); // Single character
994
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000995 char *array = strstr(varyingName, "[");
996
997 if (array)
998 {
999 *array = '\0';
1000 }
1001
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001002 varyings.push_back(Varying(varyingName, input));
1003 }
1004
1005 input = strstr(input, ";");
1006 input += 2;
1007 }
1008}
1009
1010bool Program::linkVaryings()
1011{
1012 if (!mPixelHLSL || !mVertexHLSL)
1013 {
1014 return false;
1015 }
1016
1017 VaryingArray vertexVaryings;
1018 VaryingArray pixelVaryings;
1019
1020 parseVaryings("struct VS_OUTPUT\n{\n", mVertexHLSL, vertexVaryings);
1021 parseVaryings("struct PS_INPUT\n{\n", mPixelHLSL, pixelVaryings);
1022
1023 for (unsigned int out = 0; out < vertexVaryings.size(); out++)
1024 {
1025 unsigned int in;
1026 for (in = 0; in < pixelVaryings.size(); in++)
1027 {
1028 if (vertexVaryings[out].name == pixelVaryings[in].name)
1029 {
1030 pixelVaryings[in].link = out;
1031 vertexVaryings[out].link = in;
1032
1033 break;
1034 }
1035 }
1036
1037 if (in != pixelVaryings.size())
1038 {
1039 // FIXME: Verify matching type and qualifiers
1040
1041 char *outputSemantic = strstr(vertexVaryings[out].declaration, " : TEXCOORD");
1042 char *inputSemantic = strstr(pixelVaryings[in].declaration, " : TEXCOORD");
1043 outputSemantic[11] = inputSemantic[11];
1044 }
1045 else
1046 {
1047 // Comment out the declaration and output assignment
1048 vertexVaryings[out].declaration[0] = '/';
1049 vertexVaryings[out].declaration[1] = '/';
1050
1051 char outputString[256];
1052 sprintf(outputString, " output.%s = ", vertexVaryings[out].name.c_str());
1053 char *varyingOutput = strstr(mVertexHLSL, outputString);
1054
1055 varyingOutput[0] = '/';
1056 varyingOutput[1] = '/';
1057 }
1058 }
1059
1060 // Verify that each pixel varying has been linked to a vertex varying
1061 for (unsigned int in = 0; in < pixelVaryings.size(); in++)
1062 {
1063 if (pixelVaryings[in].link < 0)
1064 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001065 appendToInfoLog("Pixel varying (%s) does not match any vertex varying", pixelVaryings[in].name);
1066
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001067 return false;
1068 }
1069 }
1070
1071 return true;
1072}
1073
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001074// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1075// compiling them into binaries, determining the attribute mappings, and collecting
1076// a list of uniforms
1077void Program::link()
1078{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001079 unlink();
1080
1081 if (!mFragmentShader || !mFragmentShader->isCompiled())
1082 {
1083 return;
1084 }
1085
1086 if (!mVertexShader || !mVertexShader->isCompiled())
1087 {
1088 return;
1089 }
1090
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001091 Context *context = getContext();
1092 const char *vertexProfile = context->getVertexShaderProfile();
1093 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +00001094
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001095 const char *ps = mFragmentShader->getHLSL();
1096 const char *vs = mVertexShader->getHLSL();
1097
1098 mPixelHLSL = new char[strlen(ps) + 1];
1099 strcpy(mPixelHLSL, ps);
1100 mVertexHLSL = new char[strlen(vs) + 1];
1101 strcpy(mVertexHLSL, vs);
1102
1103 if (!linkVaryings())
1104 {
1105 return;
1106 }
1107
1108 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL, vertexProfile, &mConstantTableVS);
1109 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001110
1111 if (vertexBinary && pixelBinary)
1112 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001113 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001114 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1115 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1116
1117 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1118 {
1119 return error(GL_OUT_OF_MEMORY);
1120 }
1121
1122 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001123
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001124 vertexBinary->Release();
1125 pixelBinary->Release();
1126 vertexBinary = NULL;
1127 pixelBinary = NULL;
1128
1129 if (mVertexExecutable && mPixelExecutable)
1130 {
1131 if (!linkAttributes())
1132 {
1133 return;
1134 }
1135
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001136 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001137 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001138 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001139 }
1140
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001141 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001142 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001143 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001144 }
1145
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001146 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001147 }
1148 }
1149}
1150
1151// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1152bool Program::linkAttributes()
1153{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001154 unsigned int usedLocations = 0;
1155
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001156 // Link attributes that have a binding location
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001157 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1158 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001159 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1160 int location = getAttributeBinding(attribute.name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001161
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001162 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001163 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001164 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001165 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001166 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001167 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001168
daniel@transgaming.com85423182010-04-22 13:35:27 +00001169 mLinkedAttribute[location] = attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001170
1171 int size = AttributeVectorCount(attribute.type);
1172
1173 if (size + location > MAX_VERTEX_ATTRIBS)
1174 {
1175 appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
1176
1177 return false;
1178 }
1179
1180 for (int i = 0; i < size; i++)
1181 {
1182 usedLocations |= 1 << (location + i);
1183 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001184 }
1185 }
1186
1187 // Link attributes that don't have a binding location
1188 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS + 1; attributeIndex++)
1189 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001190 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1191 int location = getAttributeBinding(attribute.name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001192
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001193 if (!attribute.name.empty() && location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001194 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001195 int size = AttributeVectorCount(attribute.type);
1196 int availableIndex = AllocateFirstFreeBits(&usedLocations, size, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001197
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001198 if (availableIndex == -1 || availableIndex + size > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001199 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001200 appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001201
1202 return false; // Fail to link
1203 }
1204
daniel@transgaming.com85423182010-04-22 13:35:27 +00001205 mLinkedAttribute[availableIndex] = attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001206 }
1207 }
1208
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001209 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001210 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001211 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1212
1213 if (index == -1)
1214 {
1215 mSemanticIndex[attributeIndex++] = -1;
1216 }
1217 else
1218 {
1219 int size = AttributeVectorCount(mVertexShader->getAttribute(index).type);
1220
1221 for (int i = 0; i < size; i++)
1222 {
1223 mSemanticIndex[attributeIndex++] = index++;
1224 }
1225 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001226 }
1227
1228 return true;
1229}
1230
daniel@transgaming.com85423182010-04-22 13:35:27 +00001231int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001232{
1233 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1234 {
1235 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1236 {
1237 return location;
1238 }
1239 }
1240
1241 return -1;
1242}
1243
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001244bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1245{
1246 D3DXCONSTANTTABLE_DESC constantTableDescription;
1247 D3DXCONSTANT_DESC constantDescription;
1248 UINT descriptionCount = 1;
1249
1250 constantTable->GetDesc(&constantTableDescription);
1251
1252 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1253 {
1254 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1255 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1256
1257 if (!defineUniform(constantHandle, constantDescription))
1258 {
1259 return false;
1260 }
1261 }
1262
1263 return true;
1264}
1265
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001266// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001267// Returns true if succesful (uniform not already defined)
1268bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1269{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001270 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1271 {
1272 unsigned int samplerIndex = constantDescription.RegisterIndex;
1273
1274 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1275
1276 mSamplers[samplerIndex].active = true;
1277 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1278 mSamplers[samplerIndex].logicalTextureUnit = 0;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001279 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001280 }
1281
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001282 switch(constantDescription.Class)
1283 {
1284 case D3DXPC_STRUCT:
1285 {
1286 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1287 {
1288 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1289
1290 D3DXCONSTANT_DESC fieldDescription;
1291 UINT descriptionCount = 1;
1292
1293 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1294
1295 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1296 {
1297 return false;
1298 }
1299 }
1300
1301 return true;
1302 }
1303 case D3DXPC_SCALAR:
1304 case D3DXPC_VECTOR:
1305 case D3DXPC_MATRIX_COLUMNS:
1306 case D3DXPC_OBJECT:
1307 return defineUniform(constantDescription, name + constantDescription.Name);
1308 default:
1309 UNREACHABLE();
1310 return false;
1311 }
1312}
1313
1314bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1315{
1316 Uniform *uniform = createUniform(constantDescription, name);
1317
1318 if(!uniform)
1319 {
1320 return false;
1321 }
1322
1323 // Check if already defined
1324 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001325 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001326
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001327 if (location >= 0)
1328 {
1329 delete uniform;
1330
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001331 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001332 {
1333 return false;
1334 }
1335 else
1336 {
1337 return true;
1338 }
1339 }
1340
1341 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001342 unsigned int uniformIndex = mUniforms.size() - 1;
1343
1344 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1345 {
1346 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1347 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001348
1349 return true;
1350}
1351
1352Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001353{
1354 if (constantDescription.Rows == 1) // Vectors and scalars
1355 {
1356 switch (constantDescription.Type)
1357 {
1358 case D3DXPT_SAMPLER2D:
1359 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001360 switch (constantDescription.Columns)
1361 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001362 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001363 default: UNREACHABLE();
1364 }
1365 break;
1366 case D3DXPT_BOOL:
1367 switch (constantDescription.Columns)
1368 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001369 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1370 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1371 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1372 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001373 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001374 }
1375 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001376 case D3DXPT_INT:
1377 switch (constantDescription.Columns)
1378 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001379 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1380 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1381 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1382 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001383 default: UNREACHABLE();
1384 }
1385 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001386 case D3DXPT_FLOAT:
1387 switch (constantDescription.Columns)
1388 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001389 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1390 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1391 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1392 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001393 default: UNREACHABLE();
1394 }
1395 break;
1396 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001397 UNREACHABLE();
1398 }
1399 }
1400 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1401 {
1402 switch (constantDescription.Type)
1403 {
1404 case D3DXPT_FLOAT:
1405 switch (constantDescription.Rows)
1406 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001407 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1408 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1409 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001410 default: UNREACHABLE();
1411 }
1412 break;
1413 default: UNREACHABLE();
1414 }
1415 }
1416 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001417
1418 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001419}
1420
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001421// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001422std::string Program::decorate(const std::string &string)
1423{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001424 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001425 {
1426 return "_" + string;
1427 }
1428 else
1429 {
1430 return string;
1431 }
1432}
1433
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001434std::string Program::undecorate(const std::string &string)
1435{
1436 if (string.substr(0, 1) == "_")
1437 {
1438 return string.substr(1);
1439 }
1440 else
1441 {
1442 return string;
1443 }
1444}
1445
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001446bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1447{
1448 BOOL *vector = new BOOL[count];
1449 for (int i = 0; i < count; i++)
1450 {
1451 if (v[i] == GL_FALSE)
1452 vector[i] = 0;
1453 else
1454 vector[i] = 1;
1455 }
1456
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001457 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1458
1459 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1460 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001461 IDirect3DDevice9 *device = getDevice();
1462
1463 if (constantPS)
1464 {
1465 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1466 }
1467
1468 if (constantVS)
1469 {
1470 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1471 }
1472
1473 delete [] vector;
1474
1475 return true;
1476}
1477
1478bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1479{
1480 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1481
1482 for (int i = 0; i < count; i++)
1483 {
1484 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1485 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1486
1487 v += 2;
1488 }
1489
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001490 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1491
1492 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1493 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001494 IDirect3DDevice9 *device = getDevice();
1495
1496 if (constantPS)
1497 {
1498 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1499 }
1500
1501 if (constantVS)
1502 {
1503 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1504 }
1505
1506 delete[] vector;
1507
1508 return true;
1509}
1510
1511bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1512{
1513 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1514
1515 for (int i = 0; i < count; i++)
1516 {
1517 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1518 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1519 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1520
1521 v += 3;
1522 }
1523
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001524 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1525
1526 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1527 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001528 IDirect3DDevice9 *device = getDevice();
1529
1530 if (constantPS)
1531 {
1532 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1533 }
1534
1535 if (constantVS)
1536 {
1537 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1538 }
1539
1540 delete[] vector;
1541
1542 return true;
1543}
1544
1545bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1546{
1547 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1548
1549 for (int i = 0; i < count; i++)
1550 {
1551 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1552 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1553 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1554 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1555
1556 v += 3;
1557 }
1558
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001559 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1560
1561 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1562 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001563 IDirect3DDevice9 *device = getDevice();
1564
1565 if (constantPS)
1566 {
1567 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1568 }
1569
1570 if (constantVS)
1571 {
1572 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1573 }
1574
1575 delete [] vector;
1576
1577 return true;
1578}
1579
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001580bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1581{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001582 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1583
1584 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1585 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001586 IDirect3DDevice9 *device = getDevice();
1587
1588 if (constantPS)
1589 {
1590 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1591 }
1592
1593 if (constantVS)
1594 {
1595 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1596 }
1597
1598 return true;
1599}
1600
1601bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1602{
1603 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1604
1605 for (int i = 0; i < count; i++)
1606 {
1607 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1608
1609 v += 2;
1610 }
1611
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001612 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1613
1614 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1615 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001616 IDirect3DDevice9 *device = getDevice();
1617
1618 if (constantPS)
1619 {
1620 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1621 }
1622
1623 if (constantVS)
1624 {
1625 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1626 }
1627
1628 delete[] vector;
1629
1630 return true;
1631}
1632
1633bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1634{
1635 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1636
1637 for (int i = 0; i < count; i++)
1638 {
1639 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1640
1641 v += 3;
1642 }
1643
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001644 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1645
1646 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1647 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001648 IDirect3DDevice9 *device = getDevice();
1649
1650 if (constantPS)
1651 {
1652 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1653 }
1654
1655 if (constantVS)
1656 {
1657 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1658 }
1659
1660 delete[] vector;
1661
1662 return true;
1663}
1664
1665bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1666{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001667 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1668
1669 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1670 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001671 IDirect3DDevice9 *device = getDevice();
1672
1673 if (constantPS)
1674 {
1675 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
1676 }
1677
1678 if (constantVS)
1679 {
1680 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
1681 }
1682
1683 return true;
1684}
1685
1686bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
1687{
1688 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1689
1690 for (int i = 0; i < count; i++)
1691 {
1692 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
1693 value[1], value[3], 0, 0,
1694 0, 0, 1, 0,
1695 0, 0, 0, 1);
1696
1697 value += 4;
1698 }
1699
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001700 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1701
1702 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1703 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001704 IDirect3DDevice9 *device = getDevice();
1705
1706 if (constantPS)
1707 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001708 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001709 }
1710
1711 if (constantVS)
1712 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001713 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001714 }
1715
1716 delete[] matrix;
1717
1718 return true;
1719}
1720
1721bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
1722{
1723 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1724
1725 for (int i = 0; i < count; i++)
1726 {
1727 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
1728 value[1], value[4], value[7], 0,
1729 value[2], value[5], value[8], 0,
1730 0, 0, 0, 1);
1731
1732 value += 9;
1733 }
1734
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001735 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1736
1737 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1738 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001739 IDirect3DDevice9 *device = getDevice();
1740
1741 if (constantPS)
1742 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001743 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001744 }
1745
1746 if (constantVS)
1747 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001748 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001749 }
1750
1751 delete[] matrix;
1752
1753 return true;
1754}
1755
1756bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
1757{
1758 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1759
1760 for (int i = 0; i < count; i++)
1761 {
1762 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
1763 value[1], value[5], value[9], value[13],
1764 value[2], value[6], value[10], value[14],
1765 value[3], value[7], value[11], value[15]);
1766
1767 value += 16;
1768 }
1769
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001770 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1771
1772 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1773 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001774 IDirect3DDevice9 *device = getDevice();
1775
1776 if (constantPS)
1777 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001778 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001779 }
1780
1781 if (constantVS)
1782 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001783 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001784 }
1785
1786 delete[] matrix;
1787
1788 return true;
1789}
1790
1791bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
1792{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001793 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1794
1795 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1796 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001797 IDirect3DDevice9 *device = getDevice();
1798
1799 if (constantPS)
1800 {
1801 D3DXCONSTANT_DESC constantDescription;
1802 UINT descriptionCount = 1;
1803 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
1804
daniel@transgaming.com2884b782010-03-08 21:30:48 +00001805 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001806 {
1807 return false;
1808 }
1809
1810 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1811 {
1812 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
1813
1814 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
1815 {
1816 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001817
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001818 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
1819 {
1820 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1821 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001822 ASSERT(mSamplers[samplerIndex].active);
1823 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001824 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001825 }
1826 }
1827 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001828
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001829 return true;
1830 }
1831 }
1832
1833 if (constantPS)
1834 {
1835 mConstantTablePS->SetIntArray(device, constantPS, v, count);
1836 }
1837
1838 if (constantVS)
1839 {
1840 mConstantTableVS->SetIntArray(device, constantVS, v, count);
1841 }
1842
1843 return true;
1844}
1845
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001846bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
1847{
1848 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1849
1850 for (int i = 0; i < count; i++)
1851 {
1852 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
1853
1854 v += 2;
1855 }
1856
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001857 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1858
1859 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1860 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001861 IDirect3DDevice9 *device = getDevice();
1862
1863 if (constantPS)
1864 {
1865 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1866 }
1867
1868 if (constantVS)
1869 {
1870 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1871 }
1872
1873 delete[] vector;
1874
1875 return true;
1876}
1877
1878bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
1879{
1880 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1881
1882 for (int i = 0; i < count; i++)
1883 {
1884 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
1885
1886 v += 3;
1887 }
1888
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001889 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1890
1891 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1892 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001893 IDirect3DDevice9 *device = getDevice();
1894
1895 if (constantPS)
1896 {
1897 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1898 }
1899
1900 if (constantVS)
1901 {
1902 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1903 }
1904
1905 delete[] vector;
1906
1907 return true;
1908}
1909
1910bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
1911{
1912 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1913
1914 for (int i = 0; i < count; i++)
1915 {
1916 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
1917
1918 v += 4;
1919 }
1920
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001921 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1922
1923 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1924 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001925 IDirect3DDevice9 *device = getDevice();
1926
1927 if (constantPS)
1928 {
1929 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1930 }
1931
1932 if (constantVS)
1933 {
1934 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1935 }
1936
1937 delete [] vector;
1938
1939 return true;
1940}
1941
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001942void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001943{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001944 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001945 {
1946 return;
1947 }
1948
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001949 char info[1024];
1950
1951 va_list vararg;
1952 va_start(vararg, format);
1953 vsnprintf(info, sizeof(info), format, vararg);
1954 va_end(vararg);
1955
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001956 size_t infoLength = strlen(info);
1957
1958 if (!mInfoLog)
1959 {
1960 mInfoLog = new char[infoLength + 1];
1961 strcpy(mInfoLog, info);
1962 }
1963 else
1964 {
1965 size_t logLength = strlen(mInfoLog);
1966 char *newLog = new char[logLength + infoLength + 1];
1967 strcpy(newLog, mInfoLog);
1968 strcpy(newLog + logLength, info);
1969
1970 delete[] mInfoLog;
1971 mInfoLog = newLog;
1972 }
1973}
1974
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001975void Program::resetInfoLog()
1976{
1977 if (mInfoLog)
1978 {
1979 delete [] mInfoLog;
1980 }
1981}
1982
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001983// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
1984void Program::unlink(bool destroy)
1985{
1986 if (destroy) // Object being destructed
1987 {
1988 if (mFragmentShader)
1989 {
1990 mFragmentShader->detach();
1991 mFragmentShader = NULL;
1992 }
1993
1994 if (mVertexShader)
1995 {
1996 mVertexShader->detach();
1997 mVertexShader = NULL;
1998 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001999 }
2000
2001 if (mPixelExecutable)
2002 {
2003 mPixelExecutable->Release();
2004 mPixelExecutable = NULL;
2005 }
2006
2007 if (mVertexExecutable)
2008 {
2009 mVertexExecutable->Release();
2010 mVertexExecutable = NULL;
2011 }
2012
2013 if (mConstantTablePS)
2014 {
2015 mConstantTablePS->Release();
2016 mConstantTablePS = NULL;
2017 }
2018
2019 if (mConstantTableVS)
2020 {
2021 mConstantTableVS->Release();
2022 mConstantTableVS = NULL;
2023 }
2024
2025 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2026 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002027 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002028 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002029 }
2030
2031 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2032 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00002033 mSamplers[index].active = false;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00002034 mSamplers[index].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002035 }
2036
2037 while (!mUniforms.empty())
2038 {
2039 delete mUniforms.back();
2040 mUniforms.pop_back();
2041 }
2042
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002043 mUniformIndex.clear();
2044
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002045 delete[] mPixelHLSL;
2046 mPixelHLSL = NULL;
2047
2048 delete[] mVertexHLSL;
2049 mVertexHLSL = NULL;
2050
2051 delete[] mInfoLog;
2052 mInfoLog = NULL;
2053
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002054 mLinked = false;
2055}
2056
2057bool Program::isLinked()
2058{
2059 return mLinked;
2060}
2061
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002062bool Program::isValidated() const
2063{
2064 return mValidated;
2065}
2066
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002067unsigned int Program::getSerial() const
2068{
2069 return mSerial;
2070}
2071
2072unsigned int Program::issueSerial()
2073{
2074 return mCurrentSerial++;
2075}
2076
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002077int Program::getInfoLogLength() const
2078{
2079 if (!mInfoLog)
2080 {
2081 return 0;
2082 }
2083 else
2084 {
2085 return strlen(mInfoLog) + 1;
2086 }
2087}
2088
2089void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2090{
2091 int index = 0;
2092
2093 if (mInfoLog)
2094 {
2095 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2096 {
2097 infoLog[index] = mInfoLog[index];
2098 index++;
2099 }
2100 }
2101
2102 if (bufSize)
2103 {
2104 infoLog[index] = '\0';
2105 }
2106
2107 if (length)
2108 {
2109 *length = index;
2110 }
2111}
2112
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002113void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2114{
2115 int total = 0;
2116
2117 if (mVertexShader)
2118 {
2119 if (total < maxCount)
2120 {
2121 shaders[total] = mVertexShader->getHandle();
2122 }
2123
2124 total++;
2125 }
2126
2127 if (mFragmentShader)
2128 {
2129 if (total < maxCount)
2130 {
2131 shaders[total] = mFragmentShader->getHandle();
2132 }
2133
2134 total++;
2135 }
2136
2137 if (count)
2138 {
2139 *count = total;
2140 }
2141}
2142
daniel@transgaming.com85423182010-04-22 13:35:27 +00002143void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2144{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002145 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002146 for (unsigned int i = 0; i < index; i++)
2147 {
2148 do
2149 {
2150 attribute++;
2151
2152 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2153 }
2154 while (mLinkedAttribute[attribute].name.empty());
2155 }
2156
2157 if (bufsize > 0)
2158 {
2159 const char *string = mLinkedAttribute[attribute].name.c_str();
2160
2161 strncpy(name, string, bufsize);
2162 name[bufsize - 1] = '\0';
2163
2164 if (length)
2165 {
2166 *length = strlen(name);
2167 }
2168 }
2169
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002170 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002171
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002172 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002173}
2174
2175GLint Program::getActiveAttributeCount()
2176{
2177 int count = 0;
2178
2179 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2180 {
2181 if (!mLinkedAttribute[attributeIndex].name.empty())
2182 {
2183 count++;
2184 }
2185 }
2186
2187 return count;
2188}
2189
2190GLint Program::getActiveAttributeMaxLength()
2191{
2192 int maxLength = 0;
2193
2194 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2195 {
2196 if (!mLinkedAttribute[attributeIndex].name.empty())
2197 {
2198 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2199 }
2200 }
2201
2202 return maxLength;
2203}
2204
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002205void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2206{
2207 unsigned int uniform = 0;
2208 for (unsigned int i = 0; i < index; i++)
2209 {
2210 do
2211 {
2212 uniform++;
2213
2214 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2215 }
2216 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2217 }
2218
2219 if (bufsize > 0)
2220 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002221 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002222
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002223 if (mUniforms[uniform]->arraySize != 1)
2224 {
2225 string += "[0]";
2226 }
2227
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002228 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002229 name[bufsize - 1] = '\0';
2230
2231 if (length)
2232 {
2233 *length = strlen(name);
2234 }
2235 }
2236
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002237 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002238
2239 *type = mUniforms[uniform]->type;
2240}
2241
2242GLint Program::getActiveUniformCount()
2243{
2244 int count = 0;
2245
2246 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2247 {
2248 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2249 {
2250 count++;
2251 }
2252 }
2253
2254 return count;
2255}
2256
2257GLint Program::getActiveUniformMaxLength()
2258{
2259 int maxLength = 0;
2260
2261 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2262 {
2263 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2264 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002265 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002266 }
2267 }
2268
2269 return maxLength;
2270}
2271
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002272void Program::flagForDeletion()
2273{
2274 mDeleteStatus = true;
2275}
2276
2277bool Program::isFlaggedForDeletion() const
2278{
2279 return mDeleteStatus;
2280}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002281
2282void Program::validate()
2283{
2284 resetInfoLog();
2285
2286 if (!isLinked())
2287 {
2288 appendToInfoLog("Program has not been successfully linked.");
2289 mValidated = false;
2290 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002291 else
2292 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002293 applyUniforms();
2294 if (!validateSamplers())
2295 {
2296 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2297 mValidated = false;
2298 }
2299 else
2300 {
2301 mValidated = true;
2302 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002303 }
2304}
2305
2306bool Program::validateSamplers() const
2307{
2308 // if any two active samplers in a program are of different types, but refer to the same
2309 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2310 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2311 std::map<int, SamplerType> samplerMap;
2312 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2313 {
2314 if (mSamplers[i].active)
2315 {
2316 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2317 {
2318 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2319 return false;
2320 }
2321 else
2322 {
2323 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2324 }
2325 }
2326 }
2327
2328 return true;
2329}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002330}