blob: 71960b34a3ce4b3d4a67c85d217eee8b35d7310c [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.com0df16872010-05-12 16:51:08 +0000971 appendToInfoLog("%s\n", message);
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000972 TRACE("\n%s", hlsl);
973 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000974 }
975
976 return NULL;
977}
978
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000979void Program::parseVaryings(const char *structure, char *hlsl, VaryingArray &varyings)
980{
981 char *input = strstr(hlsl, structure);
982 input += strlen(structure);
983
984 while (input && *input != '}')
985 {
986 char varyingType[256];
987 char varyingName[256];
988 unsigned int semanticIndex;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000989
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000990 int matches = sscanf(input, " %s %s : TEXCOORD%d;", varyingType, varyingName, &semanticIndex);
991
992 if (matches == 3)
993 {
994 ASSERT(semanticIndex <= 9); // Single character
995
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000996 char *array = strstr(varyingName, "[");
997
998 if (array)
999 {
1000 *array = '\0';
1001 }
1002
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001003 varyings.push_back(Varying(varyingName, input));
1004 }
1005
1006 input = strstr(input, ";");
1007 input += 2;
1008 }
1009}
1010
1011bool Program::linkVaryings()
1012{
1013 if (!mPixelHLSL || !mVertexHLSL)
1014 {
1015 return false;
1016 }
1017
1018 VaryingArray vertexVaryings;
1019 VaryingArray pixelVaryings;
1020
1021 parseVaryings("struct VS_OUTPUT\n{\n", mVertexHLSL, vertexVaryings);
1022 parseVaryings("struct PS_INPUT\n{\n", mPixelHLSL, pixelVaryings);
1023
1024 for (unsigned int out = 0; out < vertexVaryings.size(); out++)
1025 {
1026 unsigned int in;
1027 for (in = 0; in < pixelVaryings.size(); in++)
1028 {
1029 if (vertexVaryings[out].name == pixelVaryings[in].name)
1030 {
1031 pixelVaryings[in].link = out;
1032 vertexVaryings[out].link = in;
1033
1034 break;
1035 }
1036 }
1037
1038 if (in != pixelVaryings.size())
1039 {
1040 // FIXME: Verify matching type and qualifiers
1041
1042 char *outputSemantic = strstr(vertexVaryings[out].declaration, " : TEXCOORD");
1043 char *inputSemantic = strstr(pixelVaryings[in].declaration, " : TEXCOORD");
1044 outputSemantic[11] = inputSemantic[11];
1045 }
1046 else
1047 {
1048 // Comment out the declaration and output assignment
1049 vertexVaryings[out].declaration[0] = '/';
1050 vertexVaryings[out].declaration[1] = '/';
1051
1052 char outputString[256];
1053 sprintf(outputString, " output.%s = ", vertexVaryings[out].name.c_str());
1054 char *varyingOutput = strstr(mVertexHLSL, outputString);
1055
1056 varyingOutput[0] = '/';
1057 varyingOutput[1] = '/';
1058 }
1059 }
1060
1061 // Verify that each pixel varying has been linked to a vertex varying
1062 for (unsigned int in = 0; in < pixelVaryings.size(); in++)
1063 {
1064 if (pixelVaryings[in].link < 0)
1065 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001066 appendToInfoLog("Pixel varying (%s) does not match any vertex varying", pixelVaryings[in].name);
1067
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001068 return false;
1069 }
1070 }
1071
1072 return true;
1073}
1074
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001075// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1076// compiling them into binaries, determining the attribute mappings, and collecting
1077// a list of uniforms
1078void Program::link()
1079{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001080 unlink();
1081
1082 if (!mFragmentShader || !mFragmentShader->isCompiled())
1083 {
1084 return;
1085 }
1086
1087 if (!mVertexShader || !mVertexShader->isCompiled())
1088 {
1089 return;
1090 }
1091
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001092 Context *context = getContext();
1093 const char *vertexProfile = context->getVertexShaderProfile();
1094 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +00001095
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001096 const char *ps = mFragmentShader->getHLSL();
1097 const char *vs = mVertexShader->getHLSL();
1098
1099 mPixelHLSL = new char[strlen(ps) + 1];
1100 strcpy(mPixelHLSL, ps);
1101 mVertexHLSL = new char[strlen(vs) + 1];
1102 strcpy(mVertexHLSL, vs);
1103
1104 if (!linkVaryings())
1105 {
1106 return;
1107 }
1108
1109 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL, vertexProfile, &mConstantTableVS);
1110 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001111
1112 if (vertexBinary && pixelBinary)
1113 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001114 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001115 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1116 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1117
1118 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1119 {
1120 return error(GL_OUT_OF_MEMORY);
1121 }
1122
1123 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001124
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001125 vertexBinary->Release();
1126 pixelBinary->Release();
1127 vertexBinary = NULL;
1128 pixelBinary = NULL;
1129
1130 if (mVertexExecutable && mPixelExecutable)
1131 {
1132 if (!linkAttributes())
1133 {
1134 return;
1135 }
1136
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001137 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001138 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001139 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001140 }
1141
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001142 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001143 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001144 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001145 }
1146
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001147 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001148 }
1149 }
1150}
1151
1152// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1153bool Program::linkAttributes()
1154{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001155 unsigned int usedLocations = 0;
1156
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001157 // Link attributes that have a binding location
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001158 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1159 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001160 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1161 int location = getAttributeBinding(attribute.name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001162
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001163 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001164 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001165 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001166 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001167 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001168 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001169
daniel@transgaming.com85423182010-04-22 13:35:27 +00001170 mLinkedAttribute[location] = attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001171
1172 int size = AttributeVectorCount(attribute.type);
1173
1174 if (size + location > MAX_VERTEX_ATTRIBS)
1175 {
1176 appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
1177
1178 return false;
1179 }
1180
1181 for (int i = 0; i < size; i++)
1182 {
1183 usedLocations |= 1 << (location + i);
1184 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001185 }
1186 }
1187
1188 // Link attributes that don't have a binding location
1189 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS + 1; attributeIndex++)
1190 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001191 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1192 int location = getAttributeBinding(attribute.name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001193
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001194 if (!attribute.name.empty() && location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001195 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001196 int size = AttributeVectorCount(attribute.type);
1197 int availableIndex = AllocateFirstFreeBits(&usedLocations, size, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001198
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001199 if (availableIndex == -1 || availableIndex + size > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001200 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001201 appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001202
1203 return false; // Fail to link
1204 }
1205
daniel@transgaming.com85423182010-04-22 13:35:27 +00001206 mLinkedAttribute[availableIndex] = attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001207 }
1208 }
1209
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001210 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001211 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001212 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1213
1214 if (index == -1)
1215 {
1216 mSemanticIndex[attributeIndex++] = -1;
1217 }
1218 else
1219 {
1220 int size = AttributeVectorCount(mVertexShader->getAttribute(index).type);
1221
1222 for (int i = 0; i < size; i++)
1223 {
1224 mSemanticIndex[attributeIndex++] = index++;
1225 }
1226 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001227 }
1228
1229 return true;
1230}
1231
daniel@transgaming.com85423182010-04-22 13:35:27 +00001232int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001233{
1234 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1235 {
1236 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1237 {
1238 return location;
1239 }
1240 }
1241
1242 return -1;
1243}
1244
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001245bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1246{
1247 D3DXCONSTANTTABLE_DESC constantTableDescription;
1248 D3DXCONSTANT_DESC constantDescription;
1249 UINT descriptionCount = 1;
1250
1251 constantTable->GetDesc(&constantTableDescription);
1252
1253 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1254 {
1255 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1256 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1257
1258 if (!defineUniform(constantHandle, constantDescription))
1259 {
1260 return false;
1261 }
1262 }
1263
1264 return true;
1265}
1266
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001267// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001268// Returns true if succesful (uniform not already defined)
1269bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1270{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001271 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1272 {
1273 unsigned int samplerIndex = constantDescription.RegisterIndex;
1274
1275 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1276
1277 mSamplers[samplerIndex].active = true;
1278 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1279 mSamplers[samplerIndex].logicalTextureUnit = 0;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001280 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001281 }
1282
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001283 switch(constantDescription.Class)
1284 {
1285 case D3DXPC_STRUCT:
1286 {
1287 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1288 {
1289 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1290
1291 D3DXCONSTANT_DESC fieldDescription;
1292 UINT descriptionCount = 1;
1293
1294 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1295
1296 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1297 {
1298 return false;
1299 }
1300 }
1301
1302 return true;
1303 }
1304 case D3DXPC_SCALAR:
1305 case D3DXPC_VECTOR:
1306 case D3DXPC_MATRIX_COLUMNS:
1307 case D3DXPC_OBJECT:
1308 return defineUniform(constantDescription, name + constantDescription.Name);
1309 default:
1310 UNREACHABLE();
1311 return false;
1312 }
1313}
1314
1315bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1316{
1317 Uniform *uniform = createUniform(constantDescription, name);
1318
1319 if(!uniform)
1320 {
1321 return false;
1322 }
1323
1324 // Check if already defined
1325 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001326 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001327
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001328 if (location >= 0)
1329 {
1330 delete uniform;
1331
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001332 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001333 {
1334 return false;
1335 }
1336 else
1337 {
1338 return true;
1339 }
1340 }
1341
1342 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001343 unsigned int uniformIndex = mUniforms.size() - 1;
1344
1345 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1346 {
1347 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1348 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001349
1350 return true;
1351}
1352
1353Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001354{
1355 if (constantDescription.Rows == 1) // Vectors and scalars
1356 {
1357 switch (constantDescription.Type)
1358 {
1359 case D3DXPT_SAMPLER2D:
1360 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001361 switch (constantDescription.Columns)
1362 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001363 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001364 default: UNREACHABLE();
1365 }
1366 break;
1367 case D3DXPT_BOOL:
1368 switch (constantDescription.Columns)
1369 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001370 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1371 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1372 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1373 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001374 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001375 }
1376 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001377 case D3DXPT_INT:
1378 switch (constantDescription.Columns)
1379 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001380 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1381 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1382 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1383 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001384 default: UNREACHABLE();
1385 }
1386 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001387 case D3DXPT_FLOAT:
1388 switch (constantDescription.Columns)
1389 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001390 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1391 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1392 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1393 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001394 default: UNREACHABLE();
1395 }
1396 break;
1397 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001398 UNREACHABLE();
1399 }
1400 }
1401 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1402 {
1403 switch (constantDescription.Type)
1404 {
1405 case D3DXPT_FLOAT:
1406 switch (constantDescription.Rows)
1407 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001408 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1409 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1410 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001411 default: UNREACHABLE();
1412 }
1413 break;
1414 default: UNREACHABLE();
1415 }
1416 }
1417 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001418
1419 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001420}
1421
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001422// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001423std::string Program::decorate(const std::string &string)
1424{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001425 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001426 {
1427 return "_" + string;
1428 }
1429 else
1430 {
1431 return string;
1432 }
1433}
1434
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001435std::string Program::undecorate(const std::string &string)
1436{
1437 if (string.substr(0, 1) == "_")
1438 {
1439 return string.substr(1);
1440 }
1441 else
1442 {
1443 return string;
1444 }
1445}
1446
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001447bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1448{
1449 BOOL *vector = new BOOL[count];
1450 for (int i = 0; i < count; i++)
1451 {
1452 if (v[i] == GL_FALSE)
1453 vector[i] = 0;
1454 else
1455 vector[i] = 1;
1456 }
1457
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001458 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1459
1460 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1461 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001462 IDirect3DDevice9 *device = getDevice();
1463
1464 if (constantPS)
1465 {
1466 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1467 }
1468
1469 if (constantVS)
1470 {
1471 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1472 }
1473
1474 delete [] vector;
1475
1476 return true;
1477}
1478
1479bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1480{
1481 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1482
1483 for (int i = 0; i < count; i++)
1484 {
1485 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1486 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1487
1488 v += 2;
1489 }
1490
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001491 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1492
1493 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1494 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001495 IDirect3DDevice9 *device = getDevice();
1496
1497 if (constantPS)
1498 {
1499 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1500 }
1501
1502 if (constantVS)
1503 {
1504 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1505 }
1506
1507 delete[] vector;
1508
1509 return true;
1510}
1511
1512bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1513{
1514 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1515
1516 for (int i = 0; i < count; i++)
1517 {
1518 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1519 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1520 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1521
1522 v += 3;
1523 }
1524
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001525 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1526
1527 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1528 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001529 IDirect3DDevice9 *device = getDevice();
1530
1531 if (constantPS)
1532 {
1533 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1534 }
1535
1536 if (constantVS)
1537 {
1538 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1539 }
1540
1541 delete[] vector;
1542
1543 return true;
1544}
1545
1546bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1547{
1548 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1549
1550 for (int i = 0; i < count; i++)
1551 {
1552 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1553 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1554 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1555 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1556
1557 v += 3;
1558 }
1559
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001560 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1561
1562 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1563 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001564 IDirect3DDevice9 *device = getDevice();
1565
1566 if (constantPS)
1567 {
1568 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1569 }
1570
1571 if (constantVS)
1572 {
1573 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1574 }
1575
1576 delete [] vector;
1577
1578 return true;
1579}
1580
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001581bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1582{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001583 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1584
1585 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1586 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001587 IDirect3DDevice9 *device = getDevice();
1588
1589 if (constantPS)
1590 {
1591 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1592 }
1593
1594 if (constantVS)
1595 {
1596 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1597 }
1598
1599 return true;
1600}
1601
1602bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1603{
1604 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1605
1606 for (int i = 0; i < count; i++)
1607 {
1608 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1609
1610 v += 2;
1611 }
1612
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001613 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1614
1615 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1616 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001617 IDirect3DDevice9 *device = getDevice();
1618
1619 if (constantPS)
1620 {
1621 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1622 }
1623
1624 if (constantVS)
1625 {
1626 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1627 }
1628
1629 delete[] vector;
1630
1631 return true;
1632}
1633
1634bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1635{
1636 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1637
1638 for (int i = 0; i < count; i++)
1639 {
1640 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1641
1642 v += 3;
1643 }
1644
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001645 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1646
1647 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1648 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001649 IDirect3DDevice9 *device = getDevice();
1650
1651 if (constantPS)
1652 {
1653 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1654 }
1655
1656 if (constantVS)
1657 {
1658 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1659 }
1660
1661 delete[] vector;
1662
1663 return true;
1664}
1665
1666bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1667{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001668 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1669
1670 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1671 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001672 IDirect3DDevice9 *device = getDevice();
1673
1674 if (constantPS)
1675 {
1676 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
1677 }
1678
1679 if (constantVS)
1680 {
1681 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
1682 }
1683
1684 return true;
1685}
1686
1687bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
1688{
1689 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1690
1691 for (int i = 0; i < count; i++)
1692 {
1693 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
1694 value[1], value[3], 0, 0,
1695 0, 0, 1, 0,
1696 0, 0, 0, 1);
1697
1698 value += 4;
1699 }
1700
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001701 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1702
1703 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1704 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001705 IDirect3DDevice9 *device = getDevice();
1706
1707 if (constantPS)
1708 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001709 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001710 }
1711
1712 if (constantVS)
1713 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001714 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001715 }
1716
1717 delete[] matrix;
1718
1719 return true;
1720}
1721
1722bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
1723{
1724 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1725
1726 for (int i = 0; i < count; i++)
1727 {
1728 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
1729 value[1], value[4], value[7], 0,
1730 value[2], value[5], value[8], 0,
1731 0, 0, 0, 1);
1732
1733 value += 9;
1734 }
1735
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001736 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1737
1738 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1739 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001740 IDirect3DDevice9 *device = getDevice();
1741
1742 if (constantPS)
1743 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001744 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001745 }
1746
1747 if (constantVS)
1748 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001749 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001750 }
1751
1752 delete[] matrix;
1753
1754 return true;
1755}
1756
1757bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
1758{
1759 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1760
1761 for (int i = 0; i < count; i++)
1762 {
1763 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
1764 value[1], value[5], value[9], value[13],
1765 value[2], value[6], value[10], value[14],
1766 value[3], value[7], value[11], value[15]);
1767
1768 value += 16;
1769 }
1770
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001771 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1772
1773 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1774 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001775 IDirect3DDevice9 *device = getDevice();
1776
1777 if (constantPS)
1778 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001779 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001780 }
1781
1782 if (constantVS)
1783 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001784 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001785 }
1786
1787 delete[] matrix;
1788
1789 return true;
1790}
1791
1792bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
1793{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001794 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1795
1796 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1797 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001798 IDirect3DDevice9 *device = getDevice();
1799
1800 if (constantPS)
1801 {
1802 D3DXCONSTANT_DESC constantDescription;
1803 UINT descriptionCount = 1;
1804 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
1805
daniel@transgaming.com2884b782010-03-08 21:30:48 +00001806 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001807 {
1808 return false;
1809 }
1810
1811 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1812 {
1813 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
1814
1815 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
1816 {
1817 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001818
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001819 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
1820 {
1821 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1822 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001823 ASSERT(mSamplers[samplerIndex].active);
1824 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001825 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001826 }
1827 }
1828 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001829
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001830 return true;
1831 }
1832 }
1833
1834 if (constantPS)
1835 {
1836 mConstantTablePS->SetIntArray(device, constantPS, v, count);
1837 }
1838
1839 if (constantVS)
1840 {
1841 mConstantTableVS->SetIntArray(device, constantVS, v, count);
1842 }
1843
1844 return true;
1845}
1846
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001847bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
1848{
1849 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1850
1851 for (int i = 0; i < count; i++)
1852 {
1853 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
1854
1855 v += 2;
1856 }
1857
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001858 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1859
1860 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1861 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001862 IDirect3DDevice9 *device = getDevice();
1863
1864 if (constantPS)
1865 {
1866 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1867 }
1868
1869 if (constantVS)
1870 {
1871 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1872 }
1873
1874 delete[] vector;
1875
1876 return true;
1877}
1878
1879bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
1880{
1881 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1882
1883 for (int i = 0; i < count; i++)
1884 {
1885 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
1886
1887 v += 3;
1888 }
1889
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001890 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1891
1892 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1893 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001894 IDirect3DDevice9 *device = getDevice();
1895
1896 if (constantPS)
1897 {
1898 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1899 }
1900
1901 if (constantVS)
1902 {
1903 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1904 }
1905
1906 delete[] vector;
1907
1908 return true;
1909}
1910
1911bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
1912{
1913 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1914
1915 for (int i = 0; i < count; i++)
1916 {
1917 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
1918
1919 v += 4;
1920 }
1921
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001922 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1923
1924 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1925 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001926 IDirect3DDevice9 *device = getDevice();
1927
1928 if (constantPS)
1929 {
1930 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1931 }
1932
1933 if (constantVS)
1934 {
1935 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1936 }
1937
1938 delete [] vector;
1939
1940 return true;
1941}
1942
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001943void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001944{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001945 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001946 {
1947 return;
1948 }
1949
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001950 char info[1024];
1951
1952 va_list vararg;
1953 va_start(vararg, format);
1954 vsnprintf(info, sizeof(info), format, vararg);
1955 va_end(vararg);
1956
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001957 size_t infoLength = strlen(info);
1958
1959 if (!mInfoLog)
1960 {
1961 mInfoLog = new char[infoLength + 1];
1962 strcpy(mInfoLog, info);
1963 }
1964 else
1965 {
1966 size_t logLength = strlen(mInfoLog);
1967 char *newLog = new char[logLength + infoLength + 1];
1968 strcpy(newLog, mInfoLog);
1969 strcpy(newLog + logLength, info);
1970
1971 delete[] mInfoLog;
1972 mInfoLog = newLog;
1973 }
1974}
1975
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001976void Program::resetInfoLog()
1977{
1978 if (mInfoLog)
1979 {
1980 delete [] mInfoLog;
1981 }
1982}
1983
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001984// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
1985void Program::unlink(bool destroy)
1986{
1987 if (destroy) // Object being destructed
1988 {
1989 if (mFragmentShader)
1990 {
1991 mFragmentShader->detach();
1992 mFragmentShader = NULL;
1993 }
1994
1995 if (mVertexShader)
1996 {
1997 mVertexShader->detach();
1998 mVertexShader = NULL;
1999 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002000 }
2001
2002 if (mPixelExecutable)
2003 {
2004 mPixelExecutable->Release();
2005 mPixelExecutable = NULL;
2006 }
2007
2008 if (mVertexExecutable)
2009 {
2010 mVertexExecutable->Release();
2011 mVertexExecutable = NULL;
2012 }
2013
2014 if (mConstantTablePS)
2015 {
2016 mConstantTablePS->Release();
2017 mConstantTablePS = NULL;
2018 }
2019
2020 if (mConstantTableVS)
2021 {
2022 mConstantTableVS->Release();
2023 mConstantTableVS = NULL;
2024 }
2025
2026 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2027 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002028 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002029 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002030 }
2031
2032 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2033 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00002034 mSamplers[index].active = false;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00002035 mSamplers[index].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002036 }
2037
2038 while (!mUniforms.empty())
2039 {
2040 delete mUniforms.back();
2041 mUniforms.pop_back();
2042 }
2043
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002044 mUniformIndex.clear();
2045
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002046 delete[] mPixelHLSL;
2047 mPixelHLSL = NULL;
2048
2049 delete[] mVertexHLSL;
2050 mVertexHLSL = NULL;
2051
2052 delete[] mInfoLog;
2053 mInfoLog = NULL;
2054
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002055 mLinked = false;
2056}
2057
2058bool Program::isLinked()
2059{
2060 return mLinked;
2061}
2062
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002063bool Program::isValidated() const
2064{
2065 return mValidated;
2066}
2067
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002068unsigned int Program::getSerial() const
2069{
2070 return mSerial;
2071}
2072
2073unsigned int Program::issueSerial()
2074{
2075 return mCurrentSerial++;
2076}
2077
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002078int Program::getInfoLogLength() const
2079{
2080 if (!mInfoLog)
2081 {
2082 return 0;
2083 }
2084 else
2085 {
2086 return strlen(mInfoLog) + 1;
2087 }
2088}
2089
2090void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2091{
2092 int index = 0;
2093
2094 if (mInfoLog)
2095 {
2096 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2097 {
2098 infoLog[index] = mInfoLog[index];
2099 index++;
2100 }
2101 }
2102
2103 if (bufSize)
2104 {
2105 infoLog[index] = '\0';
2106 }
2107
2108 if (length)
2109 {
2110 *length = index;
2111 }
2112}
2113
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002114void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2115{
2116 int total = 0;
2117
2118 if (mVertexShader)
2119 {
2120 if (total < maxCount)
2121 {
2122 shaders[total] = mVertexShader->getHandle();
2123 }
2124
2125 total++;
2126 }
2127
2128 if (mFragmentShader)
2129 {
2130 if (total < maxCount)
2131 {
2132 shaders[total] = mFragmentShader->getHandle();
2133 }
2134
2135 total++;
2136 }
2137
2138 if (count)
2139 {
2140 *count = total;
2141 }
2142}
2143
daniel@transgaming.com85423182010-04-22 13:35:27 +00002144void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2145{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002146 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002147 for (unsigned int i = 0; i < index; i++)
2148 {
2149 do
2150 {
2151 attribute++;
2152
2153 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2154 }
2155 while (mLinkedAttribute[attribute].name.empty());
2156 }
2157
2158 if (bufsize > 0)
2159 {
2160 const char *string = mLinkedAttribute[attribute].name.c_str();
2161
2162 strncpy(name, string, bufsize);
2163 name[bufsize - 1] = '\0';
2164
2165 if (length)
2166 {
2167 *length = strlen(name);
2168 }
2169 }
2170
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002171 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002172
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002173 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002174}
2175
2176GLint Program::getActiveAttributeCount()
2177{
2178 int count = 0;
2179
2180 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2181 {
2182 if (!mLinkedAttribute[attributeIndex].name.empty())
2183 {
2184 count++;
2185 }
2186 }
2187
2188 return count;
2189}
2190
2191GLint Program::getActiveAttributeMaxLength()
2192{
2193 int maxLength = 0;
2194
2195 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2196 {
2197 if (!mLinkedAttribute[attributeIndex].name.empty())
2198 {
2199 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2200 }
2201 }
2202
2203 return maxLength;
2204}
2205
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002206void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2207{
2208 unsigned int uniform = 0;
2209 for (unsigned int i = 0; i < index; i++)
2210 {
2211 do
2212 {
2213 uniform++;
2214
2215 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2216 }
2217 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2218 }
2219
2220 if (bufsize > 0)
2221 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002222 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002223
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002224 if (mUniforms[uniform]->arraySize != 1)
2225 {
2226 string += "[0]";
2227 }
2228
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002229 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002230 name[bufsize - 1] = '\0';
2231
2232 if (length)
2233 {
2234 *length = strlen(name);
2235 }
2236 }
2237
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002238 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002239
2240 *type = mUniforms[uniform]->type;
2241}
2242
2243GLint Program::getActiveUniformCount()
2244{
2245 int count = 0;
2246
2247 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2248 {
2249 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2250 {
2251 count++;
2252 }
2253 }
2254
2255 return count;
2256}
2257
2258GLint Program::getActiveUniformMaxLength()
2259{
2260 int maxLength = 0;
2261
2262 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2263 {
2264 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2265 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002266 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002267 }
2268 }
2269
2270 return maxLength;
2271}
2272
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002273void Program::flagForDeletion()
2274{
2275 mDeleteStatus = true;
2276}
2277
2278bool Program::isFlaggedForDeletion() const
2279{
2280 return mDeleteStatus;
2281}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002282
2283void Program::validate()
2284{
2285 resetInfoLog();
2286
2287 if (!isLinked())
2288 {
2289 appendToInfoLog("Program has not been successfully linked.");
2290 mValidated = false;
2291 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002292 else
2293 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002294 applyUniforms();
2295 if (!validateSamplers())
2296 {
2297 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2298 mValidated = false;
2299 }
2300 else
2301 {
2302 mValidated = true;
2303 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002304 }
2305}
2306
2307bool Program::validateSamplers() const
2308{
2309 // if any two active samplers in a program are of different types, but refer to the same
2310 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2311 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2312 std::map<int, SamplerType> samplerMap;
2313 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2314 {
2315 if (mSamplers[i].active)
2316 {
2317 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2318 {
2319 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2320 return false;
2321 }
2322 else
2323 {
2324 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2325 }
2326 }
2327 }
2328
2329 return true;
2330}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002331}