blob: 160eb8670de78ba7276642f880e1d2dd3ce0da77 [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
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000193 GLint logicalTextureUnit = -1;
194
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000195 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000197 logicalTextureUnit = mSamplers[samplerIndex].logicalTextureUnit;
198 }
199
200 if (logicalTextureUnit < MAX_TEXTURE_IMAGE_UNITS)
201 {
202 return logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000203 }
204
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000205 return -1;
206}
207
208SamplerType Program::getSamplerType(unsigned int samplerIndex)
209{
210 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
211 assert(mSamplers[samplerIndex].active);
212
213 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000214}
215
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000216bool Program::isSamplerDirty(unsigned int samplerIndex) const
217{
218 if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]))
219 {
220 return mSamplers[samplerIndex].dirty;
221 }
222 else UNREACHABLE();
223
224 return false;
225}
226
227void Program::setSamplerDirty(unsigned int samplerIndex, bool dirty)
228{
229 if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]))
230 {
231 mSamplers[samplerIndex].dirty = dirty;
232 }
233 else UNREACHABLE();
234}
235
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000236GLint Program::getUniformLocation(const char *name)
237{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000238 std::string nameStr(name);
239 int subscript = 0;
240 size_t beginB = nameStr.find('[');
241 size_t endB = nameStr.find(']');
242 if (beginB != std::string::npos && endB != std::string::npos)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000243 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000244 std::string subscrStr = nameStr.substr(beginB + 1, beginB - endB - 1);
245 nameStr.erase(beginB);
246 subscript = atoi(subscrStr.c_str());
247 }
248
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000249 nameStr = decorate(nameStr);
250
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000251 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
252 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000253 if (mUniformIndex[location].name == nameStr &&
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000254 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000255 {
256 return location;
257 }
258 }
259
260 return -1;
261}
262
263bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
264{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000265 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000266 {
267 return false;
268 }
269
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000270 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000271 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000272
273 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000274 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000275 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000276
277 if (arraySize == 1 && count > 1)
278 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
279
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000280 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000281
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000282 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
283 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000284 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000285 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000286 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000287 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000288
289 if (arraySize == 1 && count > 1)
290 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000291
292 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000293 GLboolean *boolParams = new GLboolean[count];
294
295 for (int i = 0; i < count; ++i)
296 {
297 if (v[i] == 0.0f)
298 {
299 boolParams[i] = GL_FALSE;
300 }
301 else
302 {
303 boolParams[i] = GL_TRUE;
304 }
305 }
306
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000307 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
308 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000309
310 delete [] boolParams;
311 }
312 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000313 {
314 return false;
315 }
316
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000317 return true;
318}
319
320bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
321{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000322 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000323 {
324 return false;
325 }
326
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000327 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000328 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000329
330 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000331 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000332 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000333
334 if (arraySize == 1 && count > 1)
335 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
336
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000337 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000338
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000339 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
340 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000341 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000342 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000343 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000344 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000345
346 if (arraySize == 1 && count > 1)
347 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
348
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000349 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
350
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000351 GLboolean *boolParams = new GLboolean[count * 2];
352
353 for (int i = 0; i < count * 2; ++i)
354 {
355 if (v[i] == 0.0f)
356 {
357 boolParams[i] = GL_FALSE;
358 }
359 else
360 {
361 boolParams[i] = GL_TRUE;
362 }
363 }
364
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000365 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
366 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000367
368 delete [] boolParams;
369 }
370 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000371 {
372 return false;
373 }
374
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000375 return true;
376}
377
378bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
379{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000380 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000381 {
382 return false;
383 }
384
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000385 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000386 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000387
388 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000389 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000390 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000391
392 if (arraySize == 1 && count > 1)
393 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
394
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000395 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000396
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000397 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
398 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000399 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000400 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000401 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000402 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000403
404 if (arraySize == 1 && count > 1)
405 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
406
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000407 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000408 GLboolean *boolParams = new GLboolean[count * 3];
409
410 for (int i = 0; i < count * 3; ++i)
411 {
412 if (v[i] == 0.0f)
413 {
414 boolParams[i] = GL_FALSE;
415 }
416 else
417 {
418 boolParams[i] = GL_TRUE;
419 }
420 }
421
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000422 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
423 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000424
425 delete [] boolParams;
426 }
427 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000428 {
429 return false;
430 }
431
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000432 return true;
433}
434
435bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
436{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000437 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000438 {
439 return false;
440 }
441
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000442 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000443 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000444
445 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000446 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000447 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000448
449 if (arraySize == 1 && count > 1)
450 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
451
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000452 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000453
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000454 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
455 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000456 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000457 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000458 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000459 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000460
461 if (arraySize == 1 && count > 1)
462 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
463
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000464 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000465 GLboolean *boolParams = new GLboolean[count * 4];
466
467 for (int i = 0; i < count * 4; ++i)
468 {
469 if (v[i] == 0.0f)
470 {
471 boolParams[i] = GL_FALSE;
472 }
473 else
474 {
475 boolParams[i] = GL_TRUE;
476 }
477 }
478
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000479 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
480 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000481
482 delete [] boolParams;
483 }
484 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000485 {
486 return false;
487 }
488
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000489 return true;
490}
491
492bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
493{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000494 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000495 {
496 return false;
497 }
498
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000499 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000500 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000501
502 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000503 {
504 return false;
505 }
506
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000507 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000508
509 if (arraySize == 1 && count > 1)
510 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
511
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000512 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000513
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000514 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
515 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000516
517 return true;
518}
519
520bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
521{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000522 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000523 {
524 return false;
525 }
526
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000527 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000528 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000529
530 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000531 {
532 return false;
533 }
534
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000535 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000536
537 if (arraySize == 1 && count > 1)
538 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
539
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000540 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000541
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000542 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
543 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000544
545 return true;
546}
547
548bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
549{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000550 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000551 {
552 return false;
553 }
554
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000555 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000556 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000557
558 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000559 {
560 return false;
561 }
562
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000563 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000564
565 if (arraySize == 1 && count > 1)
566 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
567
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000568 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000569
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000570 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
571 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000572
573 return true;
574}
575
576bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
577{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000578 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000579 {
580 return false;
581 }
582
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000583 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000584 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000585
586 if (targetUniform->type == GL_INT)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000587 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000588 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000589
590 if (arraySize == 1 && count > 1)
591 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
592
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000593 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000594
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000595 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
596 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000597 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000598 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000599 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000600 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000601
602 if (arraySize == 1 && count > 1)
603 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
604
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000605 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000606 GLboolean *boolParams = new GLboolean[count];
607
608 for (int i = 0; i < count; ++i)
609 {
610 if (v[i] == 0)
611 {
612 boolParams[i] = GL_FALSE;
613 }
614 else
615 {
616 boolParams[i] = GL_TRUE;
617 }
618 }
619
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000620 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
621 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000622
623 delete [] boolParams;
624 }
625 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000626 {
627 return false;
628 }
629
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000630 return true;
631}
632
633bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
634{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000635 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000636 {
637 return false;
638 }
639
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000640 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000641 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000642
643 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000644 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000645 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000646
647 if (arraySize == 1 && count > 1)
648 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
649
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000650 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000651
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000652 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
653 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000654 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000655 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000656 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000657 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000658
659 if (arraySize == 1 && count > 1)
660 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
661
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000662 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000663 GLboolean *boolParams = new GLboolean[count * 2];
664
665 for (int i = 0; i < count * 2; ++i)
666 {
667 if (v[i] == 0)
668 {
669 boolParams[i] = GL_FALSE;
670 }
671 else
672 {
673 boolParams[i] = GL_TRUE;
674 }
675 }
676
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000677 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
678 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000679
680 delete [] boolParams;
681 }
682 else
683 {
684 return false;
685 }
686
687 return true;
688}
689
690bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
691{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000692 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000693 {
694 return false;
695 }
696
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000697 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000698 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000699
700 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000701 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000702 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000703
704 if (arraySize == 1 && count > 1)
705 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
706
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000707 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000708
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000709 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
710 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000711 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000712 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000713 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000714 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000715
716 if (arraySize == 1 && count > 1)
717 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
718
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000719 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000720 GLboolean *boolParams = new GLboolean[count * 3];
721
722 for (int i = 0; i < count * 3; ++i)
723 {
724 if (v[i] == 0)
725 {
726 boolParams[i] = GL_FALSE;
727 }
728 else
729 {
730 boolParams[i] = GL_TRUE;
731 }
732 }
733
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000734 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
735 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000736
737 delete [] boolParams;
738 }
739 else
740 {
741 return false;
742 }
743
744 return true;
745}
746
747bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
748{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000749 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000750 {
751 return false;
752 }
753
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000754 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000755 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000756
757 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000758 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000759 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000760
761 if (arraySize == 1 && count > 1)
762 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
763
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000764 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000765
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000766 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
767 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000768 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000769 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000770 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000771 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000772
773 if (arraySize == 1 && count > 1)
774 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
775
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000776 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000777 GLboolean *boolParams = new GLboolean[count * 4];
778
779 for (int i = 0; i < count * 4; ++i)
780 {
781 if (v[i] == 0)
782 {
783 boolParams[i] = GL_FALSE;
784 }
785 else
786 {
787 boolParams[i] = GL_TRUE;
788 }
789 }
790
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000791 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
792 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000793
794 delete [] boolParams;
795 }
796 else
797 {
798 return false;
799 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000800
801 return true;
802}
803
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000804bool Program::getUniformfv(GLint location, GLfloat *params)
805{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000806 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000807 {
808 return false;
809 }
810
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000811 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000812
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000813 unsigned int count = UniformComponentCount(targetUniform->type);
814
815 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000816 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000817 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000818 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000819 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000820
821 for (unsigned int i = 0; i < count; ++i)
822 {
823 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
824 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000825 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000826 break;
827 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000828 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
829 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000830 break;
831 case GL_INT:
832 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000833 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000834
835 for (unsigned int i = 0; i < count; ++i)
836 {
837 params[i] = (float)intParams[i];
838 }
839 }
840 break;
841 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000842 }
843
844 return true;
845}
846
847bool Program::getUniformiv(GLint location, GLint *params)
848{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000849 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000850 {
851 return false;
852 }
853
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000854 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000855
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000856 unsigned int count = UniformComponentCount(targetUniform->type);
857
858 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000859 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000860 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000861 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000862 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000863
864 for (unsigned int i = 0; i < count; ++i)
865 {
866 params[i] = (GLint)boolParams[i];
867 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000868 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000869 break;
870 case GL_FLOAT:
871 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000872 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000873
874 for (unsigned int i = 0; i < count; ++i)
875 {
876 params[i] = (GLint)floatParams[i];
877 }
878 }
879 break;
880 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000881 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
882 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000883 break;
884 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000885 }
886
887 return true;
888}
889
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000890void Program::dirtyAllUniforms()
891{
892 for (unsigned int index = 0; index < mUniforms.size(); index++)
893 {
894 mUniforms[index]->dirty = true;
895 }
896}
897
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000898void Program::dirtyAllSamplers()
899{
900 for (unsigned int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; ++index)
901 {
902 mSamplers[index].dirty = true;
903 }
904}
905
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000906// Applies all the uniforms set for this program object to the Direct3D 9 device
907void Program::applyUniforms()
908{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000909 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000910 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000911 if (mUniformIndex[location].element != 0)
912 {
913 continue;
914 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000915
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000916 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
917
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000918 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000919 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000920 int arraySize = targetUniform->arraySize;
921 GLfloat *f = (GLfloat*)targetUniform->data;
922 GLint *i = (GLint*)targetUniform->data;
923 GLboolean *b = (GLboolean*)targetUniform->data;
924
925 switch (targetUniform->type)
926 {
927 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
928 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
929 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
930 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
931 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
932 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
933 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
934 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
935 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
936 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
937 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
938 case GL_INT: applyUniform1iv(location, arraySize, i); break;
939 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
940 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
941 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
942 default:
943 UNREACHABLE();
944 }
945
946 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000947 }
948 }
949}
950
951// Compiles the HLSL code of the attached shaders into executable binaries
952ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
953{
954 if (!hlsl)
955 {
956 return NULL;
957 }
958
959 ID3DXBuffer *binary = NULL;
960 ID3DXBuffer *errorMessage = NULL;
961
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000962 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, NULL, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000963
964 if (SUCCEEDED(result))
965 {
966 return binary;
967 }
968
969 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
970 {
971 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
972 }
973
974 if (errorMessage)
975 {
976 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000977
daniel@transgaming.com0df16872010-05-12 16:51:08 +0000978 appendToInfoLog("%s\n", message);
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000979 TRACE("\n%s", hlsl);
980 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000981 }
982
983 return NULL;
984}
985
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000986void Program::parseVaryings(const char *structure, char *hlsl, VaryingArray &varyings)
987{
988 char *input = strstr(hlsl, structure);
989 input += strlen(structure);
990
991 while (input && *input != '}')
992 {
993 char varyingType[256];
994 char varyingName[256];
995 unsigned int semanticIndex;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000996
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000997 int matches = sscanf(input, " %s %s : TEXCOORD%d;", varyingType, varyingName, &semanticIndex);
998
999 if (matches == 3)
1000 {
1001 ASSERT(semanticIndex <= 9); // Single character
1002
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001003 char *array = strstr(varyingName, "[");
1004
1005 if (array)
1006 {
1007 *array = '\0';
1008 }
1009
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001010 varyings.push_back(Varying(varyingName, input));
1011 }
1012
1013 input = strstr(input, ";");
1014 input += 2;
1015 }
1016}
1017
1018bool Program::linkVaryings()
1019{
1020 if (!mPixelHLSL || !mVertexHLSL)
1021 {
1022 return false;
1023 }
1024
1025 VaryingArray vertexVaryings;
1026 VaryingArray pixelVaryings;
1027
1028 parseVaryings("struct VS_OUTPUT\n{\n", mVertexHLSL, vertexVaryings);
1029 parseVaryings("struct PS_INPUT\n{\n", mPixelHLSL, pixelVaryings);
1030
1031 for (unsigned int out = 0; out < vertexVaryings.size(); out++)
1032 {
1033 unsigned int in;
1034 for (in = 0; in < pixelVaryings.size(); in++)
1035 {
1036 if (vertexVaryings[out].name == pixelVaryings[in].name)
1037 {
1038 pixelVaryings[in].link = out;
1039 vertexVaryings[out].link = in;
1040
1041 break;
1042 }
1043 }
1044
1045 if (in != pixelVaryings.size())
1046 {
1047 // FIXME: Verify matching type and qualifiers
1048
1049 char *outputSemantic = strstr(vertexVaryings[out].declaration, " : TEXCOORD");
1050 char *inputSemantic = strstr(pixelVaryings[in].declaration, " : TEXCOORD");
1051 outputSemantic[11] = inputSemantic[11];
1052 }
1053 else
1054 {
1055 // Comment out the declaration and output assignment
1056 vertexVaryings[out].declaration[0] = '/';
1057 vertexVaryings[out].declaration[1] = '/';
1058
1059 char outputString[256];
1060 sprintf(outputString, " output.%s = ", vertexVaryings[out].name.c_str());
1061 char *varyingOutput = strstr(mVertexHLSL, outputString);
1062
1063 varyingOutput[0] = '/';
1064 varyingOutput[1] = '/';
1065 }
1066 }
1067
1068 // Verify that each pixel varying has been linked to a vertex varying
1069 for (unsigned int in = 0; in < pixelVaryings.size(); in++)
1070 {
1071 if (pixelVaryings[in].link < 0)
1072 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001073 appendToInfoLog("Pixel varying (%s) does not match any vertex varying", pixelVaryings[in].name);
1074
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001075 return false;
1076 }
1077 }
1078
1079 return true;
1080}
1081
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001082// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1083// compiling them into binaries, determining the attribute mappings, and collecting
1084// a list of uniforms
1085void Program::link()
1086{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001087 unlink();
1088
1089 if (!mFragmentShader || !mFragmentShader->isCompiled())
1090 {
1091 return;
1092 }
1093
1094 if (!mVertexShader || !mVertexShader->isCompiled())
1095 {
1096 return;
1097 }
1098
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001099 Context *context = getContext();
1100 const char *vertexProfile = context->getVertexShaderProfile();
1101 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +00001102
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001103 const char *ps = mFragmentShader->getHLSL();
1104 const char *vs = mVertexShader->getHLSL();
1105
1106 mPixelHLSL = new char[strlen(ps) + 1];
1107 strcpy(mPixelHLSL, ps);
1108 mVertexHLSL = new char[strlen(vs) + 1];
1109 strcpy(mVertexHLSL, vs);
1110
1111 if (!linkVaryings())
1112 {
1113 return;
1114 }
1115
1116 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL, vertexProfile, &mConstantTableVS);
1117 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001118
1119 if (vertexBinary && pixelBinary)
1120 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001121 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001122 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1123 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1124
1125 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1126 {
1127 return error(GL_OUT_OF_MEMORY);
1128 }
1129
1130 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001131
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001132 vertexBinary->Release();
1133 pixelBinary->Release();
1134 vertexBinary = NULL;
1135 pixelBinary = NULL;
1136
1137 if (mVertexExecutable && mPixelExecutable)
1138 {
1139 if (!linkAttributes())
1140 {
1141 return;
1142 }
1143
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001144 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001145 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001146 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001147 }
1148
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001149 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001150 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001151 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001152 }
1153
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001154 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001155 }
1156 }
1157}
1158
1159// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1160bool Program::linkAttributes()
1161{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001162 unsigned int usedLocations = 0;
1163
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001164 // Link attributes that have a binding location
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001165 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1166 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001167 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1168 int location = getAttributeBinding(attribute.name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001169
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001170 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001171 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001172 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001173 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001174 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001175 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001176
daniel@transgaming.com85423182010-04-22 13:35:27 +00001177 mLinkedAttribute[location] = attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001178
1179 int size = AttributeVectorCount(attribute.type);
1180
1181 if (size + location > MAX_VERTEX_ATTRIBS)
1182 {
1183 appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
1184
1185 return false;
1186 }
1187
1188 for (int i = 0; i < size; i++)
1189 {
1190 usedLocations |= 1 << (location + i);
1191 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001192 }
1193 }
1194
1195 // Link attributes that don't have a binding location
1196 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS + 1; attributeIndex++)
1197 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001198 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1199 int location = getAttributeBinding(attribute.name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001200
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001201 if (!attribute.name.empty() && location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001202 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001203 int size = AttributeVectorCount(attribute.type);
1204 int availableIndex = AllocateFirstFreeBits(&usedLocations, size, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001205
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001206 if (availableIndex == -1 || availableIndex + size > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001207 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001208 appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001209
1210 return false; // Fail to link
1211 }
1212
daniel@transgaming.com85423182010-04-22 13:35:27 +00001213 mLinkedAttribute[availableIndex] = attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001214 }
1215 }
1216
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001217 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001218 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001219 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1220
1221 if (index == -1)
1222 {
1223 mSemanticIndex[attributeIndex++] = -1;
1224 }
1225 else
1226 {
1227 int size = AttributeVectorCount(mVertexShader->getAttribute(index).type);
1228
1229 for (int i = 0; i < size; i++)
1230 {
1231 mSemanticIndex[attributeIndex++] = index++;
1232 }
1233 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001234 }
1235
1236 return true;
1237}
1238
daniel@transgaming.com85423182010-04-22 13:35:27 +00001239int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001240{
1241 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1242 {
1243 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1244 {
1245 return location;
1246 }
1247 }
1248
1249 return -1;
1250}
1251
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001252bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1253{
1254 D3DXCONSTANTTABLE_DESC constantTableDescription;
1255 D3DXCONSTANT_DESC constantDescription;
1256 UINT descriptionCount = 1;
1257
1258 constantTable->GetDesc(&constantTableDescription);
1259
1260 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1261 {
1262 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1263 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1264
1265 if (!defineUniform(constantHandle, constantDescription))
1266 {
1267 return false;
1268 }
1269 }
1270
1271 return true;
1272}
1273
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001274// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001275// Returns true if succesful (uniform not already defined)
1276bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1277{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001278 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1279 {
1280 unsigned int samplerIndex = constantDescription.RegisterIndex;
1281
1282 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1283
1284 mSamplers[samplerIndex].active = true;
1285 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1286 mSamplers[samplerIndex].logicalTextureUnit = 0;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001287 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001288 }
1289
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001290 switch(constantDescription.Class)
1291 {
1292 case D3DXPC_STRUCT:
1293 {
1294 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1295 {
1296 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1297
1298 D3DXCONSTANT_DESC fieldDescription;
1299 UINT descriptionCount = 1;
1300
1301 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1302
1303 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1304 {
1305 return false;
1306 }
1307 }
1308
1309 return true;
1310 }
1311 case D3DXPC_SCALAR:
1312 case D3DXPC_VECTOR:
1313 case D3DXPC_MATRIX_COLUMNS:
1314 case D3DXPC_OBJECT:
1315 return defineUniform(constantDescription, name + constantDescription.Name);
1316 default:
1317 UNREACHABLE();
1318 return false;
1319 }
1320}
1321
1322bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1323{
1324 Uniform *uniform = createUniform(constantDescription, name);
1325
1326 if(!uniform)
1327 {
1328 return false;
1329 }
1330
1331 // Check if already defined
1332 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001333 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001334
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001335 if (location >= 0)
1336 {
1337 delete uniform;
1338
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001339 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001340 {
1341 return false;
1342 }
1343 else
1344 {
1345 return true;
1346 }
1347 }
1348
1349 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001350 unsigned int uniformIndex = mUniforms.size() - 1;
1351
1352 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1353 {
1354 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1355 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001356
1357 return true;
1358}
1359
1360Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001361{
1362 if (constantDescription.Rows == 1) // Vectors and scalars
1363 {
1364 switch (constantDescription.Type)
1365 {
1366 case D3DXPT_SAMPLER2D:
1367 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001368 switch (constantDescription.Columns)
1369 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001370 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001371 default: UNREACHABLE();
1372 }
1373 break;
1374 case D3DXPT_BOOL:
1375 switch (constantDescription.Columns)
1376 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001377 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1378 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1379 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1380 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001381 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001382 }
1383 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001384 case D3DXPT_INT:
1385 switch (constantDescription.Columns)
1386 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001387 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1388 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1389 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1390 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001391 default: UNREACHABLE();
1392 }
1393 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001394 case D3DXPT_FLOAT:
1395 switch (constantDescription.Columns)
1396 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001397 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1398 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1399 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1400 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001401 default: UNREACHABLE();
1402 }
1403 break;
1404 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001405 UNREACHABLE();
1406 }
1407 }
1408 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1409 {
1410 switch (constantDescription.Type)
1411 {
1412 case D3DXPT_FLOAT:
1413 switch (constantDescription.Rows)
1414 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001415 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1416 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1417 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001418 default: UNREACHABLE();
1419 }
1420 break;
1421 default: UNREACHABLE();
1422 }
1423 }
1424 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001425
1426 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001427}
1428
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001429// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001430std::string Program::decorate(const std::string &string)
1431{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001432 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001433 {
1434 return "_" + string;
1435 }
1436 else
1437 {
1438 return string;
1439 }
1440}
1441
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001442std::string Program::undecorate(const std::string &string)
1443{
1444 if (string.substr(0, 1) == "_")
1445 {
1446 return string.substr(1);
1447 }
1448 else
1449 {
1450 return string;
1451 }
1452}
1453
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001454bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1455{
1456 BOOL *vector = new BOOL[count];
1457 for (int i = 0; i < count; i++)
1458 {
1459 if (v[i] == GL_FALSE)
1460 vector[i] = 0;
1461 else
1462 vector[i] = 1;
1463 }
1464
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001465 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1466
1467 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1468 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001469 IDirect3DDevice9 *device = getDevice();
1470
1471 if (constantPS)
1472 {
1473 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1474 }
1475
1476 if (constantVS)
1477 {
1478 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1479 }
1480
1481 delete [] vector;
1482
1483 return true;
1484}
1485
1486bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1487{
1488 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1489
1490 for (int i = 0; i < count; i++)
1491 {
1492 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1493 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1494
1495 v += 2;
1496 }
1497
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001498 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1499
1500 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1501 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001502 IDirect3DDevice9 *device = getDevice();
1503
1504 if (constantPS)
1505 {
1506 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1507 }
1508
1509 if (constantVS)
1510 {
1511 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1512 }
1513
1514 delete[] vector;
1515
1516 return true;
1517}
1518
1519bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1520{
1521 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1522
1523 for (int i = 0; i < count; i++)
1524 {
1525 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1526 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1527 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1528
1529 v += 3;
1530 }
1531
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001532 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1533
1534 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1535 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001536 IDirect3DDevice9 *device = getDevice();
1537
1538 if (constantPS)
1539 {
1540 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1541 }
1542
1543 if (constantVS)
1544 {
1545 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1546 }
1547
1548 delete[] vector;
1549
1550 return true;
1551}
1552
1553bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1554{
1555 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1556
1557 for (int i = 0; i < count; i++)
1558 {
1559 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1560 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1561 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1562 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1563
1564 v += 3;
1565 }
1566
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001567 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1568
1569 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1570 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001571 IDirect3DDevice9 *device = getDevice();
1572
1573 if (constantPS)
1574 {
1575 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1576 }
1577
1578 if (constantVS)
1579 {
1580 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1581 }
1582
1583 delete [] vector;
1584
1585 return true;
1586}
1587
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001588bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1589{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001590 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1591
1592 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1593 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001594 IDirect3DDevice9 *device = getDevice();
1595
1596 if (constantPS)
1597 {
1598 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1599 }
1600
1601 if (constantVS)
1602 {
1603 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1604 }
1605
1606 return true;
1607}
1608
1609bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1610{
1611 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1612
1613 for (int i = 0; i < count; i++)
1614 {
1615 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1616
1617 v += 2;
1618 }
1619
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001620 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1621
1622 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1623 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001624 IDirect3DDevice9 *device = getDevice();
1625
1626 if (constantPS)
1627 {
1628 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1629 }
1630
1631 if (constantVS)
1632 {
1633 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1634 }
1635
1636 delete[] vector;
1637
1638 return true;
1639}
1640
1641bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1642{
1643 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1644
1645 for (int i = 0; i < count; i++)
1646 {
1647 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1648
1649 v += 3;
1650 }
1651
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001652 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1653
1654 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1655 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001656 IDirect3DDevice9 *device = getDevice();
1657
1658 if (constantPS)
1659 {
1660 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1661 }
1662
1663 if (constantVS)
1664 {
1665 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1666 }
1667
1668 delete[] vector;
1669
1670 return true;
1671}
1672
1673bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1674{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001675 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1676
1677 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1678 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001679 IDirect3DDevice9 *device = getDevice();
1680
1681 if (constantPS)
1682 {
1683 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
1684 }
1685
1686 if (constantVS)
1687 {
1688 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
1689 }
1690
1691 return true;
1692}
1693
1694bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
1695{
1696 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1697
1698 for (int i = 0; i < count; i++)
1699 {
1700 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
1701 value[1], value[3], 0, 0,
1702 0, 0, 1, 0,
1703 0, 0, 0, 1);
1704
1705 value += 4;
1706 }
1707
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001708 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1709
1710 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1711 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001712 IDirect3DDevice9 *device = getDevice();
1713
1714 if (constantPS)
1715 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001716 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001717 }
1718
1719 if (constantVS)
1720 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001721 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001722 }
1723
1724 delete[] matrix;
1725
1726 return true;
1727}
1728
1729bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
1730{
1731 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1732
1733 for (int i = 0; i < count; i++)
1734 {
1735 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
1736 value[1], value[4], value[7], 0,
1737 value[2], value[5], value[8], 0,
1738 0, 0, 0, 1);
1739
1740 value += 9;
1741 }
1742
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001743 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1744
1745 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1746 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001747 IDirect3DDevice9 *device = getDevice();
1748
1749 if (constantPS)
1750 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001751 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001752 }
1753
1754 if (constantVS)
1755 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001756 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001757 }
1758
1759 delete[] matrix;
1760
1761 return true;
1762}
1763
1764bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
1765{
1766 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1767
1768 for (int i = 0; i < count; i++)
1769 {
1770 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
1771 value[1], value[5], value[9], value[13],
1772 value[2], value[6], value[10], value[14],
1773 value[3], value[7], value[11], value[15]);
1774
1775 value += 16;
1776 }
1777
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001778 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1779
1780 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1781 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001782 IDirect3DDevice9 *device = getDevice();
1783
1784 if (constantPS)
1785 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001786 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001787 }
1788
1789 if (constantVS)
1790 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001791 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001792 }
1793
1794 delete[] matrix;
1795
1796 return true;
1797}
1798
1799bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
1800{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001801 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1802
1803 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1804 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001805 IDirect3DDevice9 *device = getDevice();
1806
1807 if (constantPS)
1808 {
1809 D3DXCONSTANT_DESC constantDescription;
1810 UINT descriptionCount = 1;
1811 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
1812
daniel@transgaming.com2884b782010-03-08 21:30:48 +00001813 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001814 {
1815 return false;
1816 }
1817
1818 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1819 {
1820 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
1821
1822 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
1823 {
1824 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001825
daniel@transgaming.com4071e662010-05-12 16:51:16 +00001826 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001827 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +00001828 ASSERT(mSamplers[samplerIndex].active);
1829 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
1830 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001831 }
1832 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001833
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001834 return true;
1835 }
1836 }
1837
1838 if (constantPS)
1839 {
1840 mConstantTablePS->SetIntArray(device, constantPS, v, count);
1841 }
1842
1843 if (constantVS)
1844 {
1845 mConstantTableVS->SetIntArray(device, constantVS, v, count);
1846 }
1847
1848 return true;
1849}
1850
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001851bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
1852{
1853 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1854
1855 for (int i = 0; i < count; i++)
1856 {
1857 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
1858
1859 v += 2;
1860 }
1861
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001862 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1863
1864 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1865 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001866 IDirect3DDevice9 *device = getDevice();
1867
1868 if (constantPS)
1869 {
1870 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1871 }
1872
1873 if (constantVS)
1874 {
1875 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1876 }
1877
1878 delete[] vector;
1879
1880 return true;
1881}
1882
1883bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
1884{
1885 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1886
1887 for (int i = 0; i < count; i++)
1888 {
1889 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
1890
1891 v += 3;
1892 }
1893
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001894 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1895
1896 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1897 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001898 IDirect3DDevice9 *device = getDevice();
1899
1900 if (constantPS)
1901 {
1902 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1903 }
1904
1905 if (constantVS)
1906 {
1907 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1908 }
1909
1910 delete[] vector;
1911
1912 return true;
1913}
1914
1915bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
1916{
1917 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1918
1919 for (int i = 0; i < count; i++)
1920 {
1921 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
1922
1923 v += 4;
1924 }
1925
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001926 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1927
1928 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1929 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001930 IDirect3DDevice9 *device = getDevice();
1931
1932 if (constantPS)
1933 {
1934 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1935 }
1936
1937 if (constantVS)
1938 {
1939 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1940 }
1941
1942 delete [] vector;
1943
1944 return true;
1945}
1946
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001947void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001948{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001949 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001950 {
1951 return;
1952 }
1953
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001954 char info[1024];
1955
1956 va_list vararg;
1957 va_start(vararg, format);
1958 vsnprintf(info, sizeof(info), format, vararg);
1959 va_end(vararg);
1960
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001961 size_t infoLength = strlen(info);
1962
1963 if (!mInfoLog)
1964 {
1965 mInfoLog = new char[infoLength + 1];
1966 strcpy(mInfoLog, info);
1967 }
1968 else
1969 {
1970 size_t logLength = strlen(mInfoLog);
1971 char *newLog = new char[logLength + infoLength + 1];
1972 strcpy(newLog, mInfoLog);
1973 strcpy(newLog + logLength, info);
1974
1975 delete[] mInfoLog;
1976 mInfoLog = newLog;
1977 }
1978}
1979
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001980void Program::resetInfoLog()
1981{
1982 if (mInfoLog)
1983 {
1984 delete [] mInfoLog;
1985 }
1986}
1987
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001988// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
1989void Program::unlink(bool destroy)
1990{
1991 if (destroy) // Object being destructed
1992 {
1993 if (mFragmentShader)
1994 {
1995 mFragmentShader->detach();
1996 mFragmentShader = NULL;
1997 }
1998
1999 if (mVertexShader)
2000 {
2001 mVertexShader->detach();
2002 mVertexShader = NULL;
2003 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002004 }
2005
2006 if (mPixelExecutable)
2007 {
2008 mPixelExecutable->Release();
2009 mPixelExecutable = NULL;
2010 }
2011
2012 if (mVertexExecutable)
2013 {
2014 mVertexExecutable->Release();
2015 mVertexExecutable = NULL;
2016 }
2017
2018 if (mConstantTablePS)
2019 {
2020 mConstantTablePS->Release();
2021 mConstantTablePS = NULL;
2022 }
2023
2024 if (mConstantTableVS)
2025 {
2026 mConstantTableVS->Release();
2027 mConstantTableVS = NULL;
2028 }
2029
2030 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2031 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002032 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002033 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002034 }
2035
2036 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2037 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00002038 mSamplers[index].active = false;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00002039 mSamplers[index].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002040 }
2041
2042 while (!mUniforms.empty())
2043 {
2044 delete mUniforms.back();
2045 mUniforms.pop_back();
2046 }
2047
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002048 mUniformIndex.clear();
2049
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002050 delete[] mPixelHLSL;
2051 mPixelHLSL = NULL;
2052
2053 delete[] mVertexHLSL;
2054 mVertexHLSL = NULL;
2055
2056 delete[] mInfoLog;
2057 mInfoLog = NULL;
2058
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002059 mLinked = false;
2060}
2061
2062bool Program::isLinked()
2063{
2064 return mLinked;
2065}
2066
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002067bool Program::isValidated() const
2068{
2069 return mValidated;
2070}
2071
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002072unsigned int Program::getSerial() const
2073{
2074 return mSerial;
2075}
2076
2077unsigned int Program::issueSerial()
2078{
2079 return mCurrentSerial++;
2080}
2081
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002082int Program::getInfoLogLength() const
2083{
2084 if (!mInfoLog)
2085 {
2086 return 0;
2087 }
2088 else
2089 {
2090 return strlen(mInfoLog) + 1;
2091 }
2092}
2093
2094void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2095{
2096 int index = 0;
2097
2098 if (mInfoLog)
2099 {
2100 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2101 {
2102 infoLog[index] = mInfoLog[index];
2103 index++;
2104 }
2105 }
2106
2107 if (bufSize)
2108 {
2109 infoLog[index] = '\0';
2110 }
2111
2112 if (length)
2113 {
2114 *length = index;
2115 }
2116}
2117
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002118void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2119{
2120 int total = 0;
2121
2122 if (mVertexShader)
2123 {
2124 if (total < maxCount)
2125 {
2126 shaders[total] = mVertexShader->getHandle();
2127 }
2128
2129 total++;
2130 }
2131
2132 if (mFragmentShader)
2133 {
2134 if (total < maxCount)
2135 {
2136 shaders[total] = mFragmentShader->getHandle();
2137 }
2138
2139 total++;
2140 }
2141
2142 if (count)
2143 {
2144 *count = total;
2145 }
2146}
2147
daniel@transgaming.com85423182010-04-22 13:35:27 +00002148void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2149{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002150 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002151 for (unsigned int i = 0; i < index; i++)
2152 {
2153 do
2154 {
2155 attribute++;
2156
2157 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2158 }
2159 while (mLinkedAttribute[attribute].name.empty());
2160 }
2161
2162 if (bufsize > 0)
2163 {
2164 const char *string = mLinkedAttribute[attribute].name.c_str();
2165
2166 strncpy(name, string, bufsize);
2167 name[bufsize - 1] = '\0';
2168
2169 if (length)
2170 {
2171 *length = strlen(name);
2172 }
2173 }
2174
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002175 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002176
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002177 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002178}
2179
2180GLint Program::getActiveAttributeCount()
2181{
2182 int count = 0;
2183
2184 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2185 {
2186 if (!mLinkedAttribute[attributeIndex].name.empty())
2187 {
2188 count++;
2189 }
2190 }
2191
2192 return count;
2193}
2194
2195GLint Program::getActiveAttributeMaxLength()
2196{
2197 int maxLength = 0;
2198
2199 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2200 {
2201 if (!mLinkedAttribute[attributeIndex].name.empty())
2202 {
2203 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2204 }
2205 }
2206
2207 return maxLength;
2208}
2209
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002210void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2211{
2212 unsigned int uniform = 0;
2213 for (unsigned int i = 0; i < index; i++)
2214 {
2215 do
2216 {
2217 uniform++;
2218
2219 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2220 }
2221 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2222 }
2223
2224 if (bufsize > 0)
2225 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002226 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002227
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002228 if (mUniforms[uniform]->arraySize != 1)
2229 {
2230 string += "[0]";
2231 }
2232
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002233 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002234 name[bufsize - 1] = '\0';
2235
2236 if (length)
2237 {
2238 *length = strlen(name);
2239 }
2240 }
2241
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002242 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002243
2244 *type = mUniforms[uniform]->type;
2245}
2246
2247GLint Program::getActiveUniformCount()
2248{
2249 int count = 0;
2250
2251 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2252 {
2253 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2254 {
2255 count++;
2256 }
2257 }
2258
2259 return count;
2260}
2261
2262GLint Program::getActiveUniformMaxLength()
2263{
2264 int maxLength = 0;
2265
2266 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2267 {
2268 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2269 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002270 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002271 }
2272 }
2273
2274 return maxLength;
2275}
2276
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002277void Program::flagForDeletion()
2278{
2279 mDeleteStatus = true;
2280}
2281
2282bool Program::isFlaggedForDeletion() const
2283{
2284 return mDeleteStatus;
2285}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002286
2287void Program::validate()
2288{
2289 resetInfoLog();
2290
2291 if (!isLinked())
2292 {
2293 appendToInfoLog("Program has not been successfully linked.");
2294 mValidated = false;
2295 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002296 else
2297 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002298 applyUniforms();
2299 if (!validateSamplers())
2300 {
2301 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2302 mValidated = false;
2303 }
2304 else
2305 {
2306 mValidated = true;
2307 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002308 }
2309}
2310
2311bool Program::validateSamplers() const
2312{
2313 // if any two active samplers in a program are of different types, but refer to the same
2314 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2315 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2316 std::map<int, SamplerType> samplerMap;
2317 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2318 {
2319 if (mSamplers[i].active)
2320 {
2321 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2322 {
2323 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2324 return false;
2325 }
2326 else
2327 {
2328 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2329 }
2330 }
2331 }
2332
2333 return true;
2334}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002335}