blob: b709dbcb4a3e0b7d9b7c23c18ea6002c3e2ed3ed [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.com4af7acc2010-05-14 17:30:53 +000022std::string str(int i)
23{
24 char buffer[20];
25 sprintf(buffer, "%d", i);
26 return buffer;
27}
28
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000029Uniform::Uniform(GLenum type, const std::string &name, unsigned int arraySize) : type(type), name(name), arraySize(arraySize)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000030{
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000031 int bytes = UniformTypeSize(type) * arraySize;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000032 data = new unsigned char[bytes];
33 memset(data, 0, bytes);
34 dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000035}
36
37Uniform::~Uniform()
38{
39 delete[] data;
40}
41
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +000042UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
43 : name(name), element(element), index(index)
44{
45}
46
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000047Program::Program()
48{
49 mFragmentShader = NULL;
50 mVertexShader = NULL;
51
52 mPixelExecutable = NULL;
53 mVertexExecutable = NULL;
54 mConstantTablePS = NULL;
55 mConstantTableVS = NULL;
56
daniel@transgaming.comcba50572010-03-28 19:36:09 +000057 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +000058 mValidated = false;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000059
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000060 unlink();
61
62 mDeleteStatus = false;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000063
64 mSerial = issueSerial();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000065}
66
67Program::~Program()
68{
69 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000070
71 if (mVertexShader != NULL)
72 {
73 mVertexShader->detach();
74 }
75
76 if (mFragmentShader != NULL)
77 {
78 mFragmentShader->detach();
79 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000080}
81
82bool Program::attachShader(Shader *shader)
83{
84 if (shader->getType() == GL_VERTEX_SHADER)
85 {
86 if (mVertexShader)
87 {
88 return false;
89 }
90
91 mVertexShader = (VertexShader*)shader;
92 mVertexShader->attach();
93 }
94 else if (shader->getType() == GL_FRAGMENT_SHADER)
95 {
96 if (mFragmentShader)
97 {
98 return false;
99 }
100
101 mFragmentShader = (FragmentShader*)shader;
102 mFragmentShader->attach();
103 }
104 else UNREACHABLE();
105
106 return true;
107}
108
109bool Program::detachShader(Shader *shader)
110{
111 if (shader->getType() == GL_VERTEX_SHADER)
112 {
113 if (mVertexShader != shader)
114 {
115 return false;
116 }
117
118 mVertexShader->detach();
119 mVertexShader = NULL;
120 }
121 else if (shader->getType() == GL_FRAGMENT_SHADER)
122 {
123 if (mFragmentShader != shader)
124 {
125 return false;
126 }
127
128 mFragmentShader->detach();
129 mFragmentShader = NULL;
130 }
131 else UNREACHABLE();
132
133 unlink();
134
135 return true;
136}
137
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000138int Program::getAttachedShadersCount() const
139{
140 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
141}
142
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143IDirect3DPixelShader9 *Program::getPixelShader()
144{
145 return mPixelExecutable;
146}
147
148IDirect3DVertexShader9 *Program::getVertexShader()
149{
150 return mVertexExecutable;
151}
152
153void Program::bindAttributeLocation(GLuint index, const char *name)
154{
155 if (index < MAX_VERTEX_ATTRIBS)
156 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000157 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
158 {
159 mAttributeBinding[i].erase(name);
160 }
161
162 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000163 }
164}
165
166GLuint Program::getAttributeLocation(const char *name)
167{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000168 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000169 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000170 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000172 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000173 {
174 return index;
175 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000176 }
177 }
178
179 return -1;
180}
181
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000182int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000183{
184 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
185 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000186 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000187 }
188
189 return -1;
190}
191
192// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
193// index referenced in the compiled HLSL shader
194GLint Program::getSamplerMapping(unsigned int samplerIndex)
195{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000196 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
197
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000198 GLint logicalTextureUnit = -1;
199
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000200 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000201 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000202 logicalTextureUnit = mSamplers[samplerIndex].logicalTextureUnit;
203 }
204
205 if (logicalTextureUnit < MAX_TEXTURE_IMAGE_UNITS)
206 {
207 return logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000208 }
209
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000210 return -1;
211}
212
213SamplerType Program::getSamplerType(unsigned int samplerIndex)
214{
215 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
216 assert(mSamplers[samplerIndex].active);
217
218 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000219}
220
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000221bool Program::isSamplerDirty(unsigned int samplerIndex) const
222{
223 if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]))
224 {
225 return mSamplers[samplerIndex].dirty;
226 }
227 else UNREACHABLE();
228
229 return false;
230}
231
232void Program::setSamplerDirty(unsigned int samplerIndex, bool dirty)
233{
234 if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]))
235 {
236 mSamplers[samplerIndex].dirty = dirty;
237 }
238 else UNREACHABLE();
239}
240
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000241GLint Program::getUniformLocation(const char *name)
242{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000243 std::string nameStr(name);
244 int subscript = 0;
245 size_t beginB = nameStr.find('[');
246 size_t endB = nameStr.find(']');
247 if (beginB != std::string::npos && endB != std::string::npos)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000248 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000249 std::string subscrStr = nameStr.substr(beginB + 1, beginB - endB - 1);
250 nameStr.erase(beginB);
251 subscript = atoi(subscrStr.c_str());
252 }
253
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000254 nameStr = decorate(nameStr);
255
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000256 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
257 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000258 if (mUniformIndex[location].name == nameStr &&
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000259 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000260 {
261 return location;
262 }
263 }
264
265 return -1;
266}
267
268bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
269{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000270 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000271 {
272 return false;
273 }
274
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000275 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000276 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000277
278 if (targetUniform->type == GL_FLOAT)
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
284
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000285 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000286
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000287 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
288 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000289 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000290 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000291 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000292 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000293
294 if (arraySize == 1 && count > 1)
295 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000296
297 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000298 GLboolean *boolParams = new GLboolean[count];
299
300 for (int i = 0; i < count; ++i)
301 {
302 if (v[i] == 0.0f)
303 {
304 boolParams[i] = GL_FALSE;
305 }
306 else
307 {
308 boolParams[i] = GL_TRUE;
309 }
310 }
311
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000312 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
313 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000314
315 delete [] boolParams;
316 }
317 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000318 {
319 return false;
320 }
321
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000322 return true;
323}
324
325bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
326{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000327 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000328 {
329 return false;
330 }
331
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000332 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000333 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000334
335 if (targetUniform->type == GL_FLOAT_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);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000343
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000344 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
345 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000346 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000347 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000348 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000349 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000350
351 if (arraySize == 1 && count > 1)
352 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
353
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000354 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
355
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000356 GLboolean *boolParams = new GLboolean[count * 2];
357
358 for (int i = 0; i < count * 2; ++i)
359 {
360 if (v[i] == 0.0f)
361 {
362 boolParams[i] = GL_FALSE;
363 }
364 else
365 {
366 boolParams[i] = GL_TRUE;
367 }
368 }
369
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000370 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
371 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000372
373 delete [] boolParams;
374 }
375 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000376 {
377 return false;
378 }
379
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000380 return true;
381}
382
383bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
384{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000385 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000386 {
387 return false;
388 }
389
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000390 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000391 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000392
393 if (targetUniform->type == GL_FLOAT_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
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000402 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
403 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000404 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000405 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000406 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000407 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000408
409 if (arraySize == 1 && count > 1)
410 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
411
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000412 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000413 GLboolean *boolParams = new GLboolean[count * 3];
414
415 for (int i = 0; i < count * 3; ++i)
416 {
417 if (v[i] == 0.0f)
418 {
419 boolParams[i] = GL_FALSE;
420 }
421 else
422 {
423 boolParams[i] = GL_TRUE;
424 }
425 }
426
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000427 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
428 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000429
430 delete [] boolParams;
431 }
432 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000433 {
434 return false;
435 }
436
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000437 return true;
438}
439
440bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
441{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000442 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000443 {
444 return false;
445 }
446
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000447 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000448 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000449
450 if (targetUniform->type == GL_FLOAT_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
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000459 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
460 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000461 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000462 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000463 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000464 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000465
466 if (arraySize == 1 && count > 1)
467 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
468
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000469 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000470 GLboolean *boolParams = new GLboolean[count * 4];
471
472 for (int i = 0; i < count * 4; ++i)
473 {
474 if (v[i] == 0.0f)
475 {
476 boolParams[i] = GL_FALSE;
477 }
478 else
479 {
480 boolParams[i] = GL_TRUE;
481 }
482 }
483
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000484 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
485 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000486
487 delete [] boolParams;
488 }
489 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000490 {
491 return false;
492 }
493
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000494 return true;
495}
496
497bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
498{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000499 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000500 {
501 return false;
502 }
503
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000504 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000505 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000506
507 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000508 {
509 return false;
510 }
511
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000512 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000513
514 if (arraySize == 1 && count > 1)
515 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
516
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000517 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000518
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000519 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
520 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000521
522 return true;
523}
524
525bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
526{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000527 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000528 {
529 return false;
530 }
531
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000532 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000533 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000534
535 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000536 {
537 return false;
538 }
539
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000540 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000541
542 if (arraySize == 1 && count > 1)
543 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
544
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000545 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000546
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000547 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
548 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000549
550 return true;
551}
552
553bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
554{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000555 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000556 {
557 return false;
558 }
559
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000560 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000561 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000562
563 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000564 {
565 return false;
566 }
567
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000568 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000569
570 if (arraySize == 1 && count > 1)
571 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
572
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000573 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000574
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000575 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
576 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000577
578 return true;
579}
580
581bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
582{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000583 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000584 {
585 return false;
586 }
587
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000588 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000589 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000590
591 if (targetUniform->type == GL_INT)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000592 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000593 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000594
595 if (arraySize == 1 && count > 1)
596 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
597
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000598 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000599
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000600 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
601 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000602 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000603 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000604 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000605 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000606
607 if (arraySize == 1 && count > 1)
608 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
609
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000610 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000611 GLboolean *boolParams = new GLboolean[count];
612
613 for (int i = 0; i < count; ++i)
614 {
615 if (v[i] == 0)
616 {
617 boolParams[i] = GL_FALSE;
618 }
619 else
620 {
621 boolParams[i] = GL_TRUE;
622 }
623 }
624
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000625 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
626 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000627
628 delete [] boolParams;
629 }
630 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000631 {
632 return false;
633 }
634
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000635 return true;
636}
637
638bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
639{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000640 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000641 {
642 return false;
643 }
644
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000645 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000646 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000647
648 if (targetUniform->type == GL_INT_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
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000657 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
658 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000659 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000660 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000661 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000662 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000663
664 if (arraySize == 1 && count > 1)
665 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
666
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000667 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000668 GLboolean *boolParams = new GLboolean[count * 2];
669
670 for (int i = 0; i < count * 2; ++i)
671 {
672 if (v[i] == 0)
673 {
674 boolParams[i] = GL_FALSE;
675 }
676 else
677 {
678 boolParams[i] = GL_TRUE;
679 }
680 }
681
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000682 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
683 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000684
685 delete [] boolParams;
686 }
687 else
688 {
689 return false;
690 }
691
692 return true;
693}
694
695bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
696{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000697 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000698 {
699 return false;
700 }
701
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000702 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000703 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000704
705 if (targetUniform->type == GL_INT_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
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000714 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
715 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000716 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000717 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000718 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000719 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000720
721 if (arraySize == 1 && count > 1)
722 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
723
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000724 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000725 GLboolean *boolParams = new GLboolean[count * 3];
726
727 for (int i = 0; i < count * 3; ++i)
728 {
729 if (v[i] == 0)
730 {
731 boolParams[i] = GL_FALSE;
732 }
733 else
734 {
735 boolParams[i] = GL_TRUE;
736 }
737 }
738
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000739 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
740 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000741
742 delete [] boolParams;
743 }
744 else
745 {
746 return false;
747 }
748
749 return true;
750}
751
752bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
753{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000754 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000755 {
756 return false;
757 }
758
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000759 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000760 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000761
762 if (targetUniform->type == GL_INT_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
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000771 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
772 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000773 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000774 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000775 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000776 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000777
778 if (arraySize == 1 && count > 1)
779 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
780
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000781 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000782 GLboolean *boolParams = new GLboolean[count * 4];
783
784 for (int i = 0; i < count * 4; ++i)
785 {
786 if (v[i] == 0)
787 {
788 boolParams[i] = GL_FALSE;
789 }
790 else
791 {
792 boolParams[i] = GL_TRUE;
793 }
794 }
795
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000796 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
797 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000798
799 delete [] boolParams;
800 }
801 else
802 {
803 return false;
804 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000805
806 return true;
807}
808
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000809bool Program::getUniformfv(GLint location, GLfloat *params)
810{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000811 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000812 {
813 return false;
814 }
815
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000816 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000817
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000818 unsigned int count = UniformComponentCount(targetUniform->type);
819
820 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000821 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000822 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000823 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000824 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000825
826 for (unsigned int i = 0; i < count; ++i)
827 {
828 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
829 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000830 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000831 break;
832 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000833 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
834 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000835 break;
836 case GL_INT:
837 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000838 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000839
840 for (unsigned int i = 0; i < count; ++i)
841 {
842 params[i] = (float)intParams[i];
843 }
844 }
845 break;
846 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000847 }
848
849 return true;
850}
851
852bool Program::getUniformiv(GLint location, GLint *params)
853{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000854 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000855 {
856 return false;
857 }
858
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000859 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000860
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000861 unsigned int count = UniformComponentCount(targetUniform->type);
862
863 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000864 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000865 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000866 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000867 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000868
869 for (unsigned int i = 0; i < count; ++i)
870 {
871 params[i] = (GLint)boolParams[i];
872 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000873 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000874 break;
875 case GL_FLOAT:
876 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000877 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000878
879 for (unsigned int i = 0; i < count; ++i)
880 {
881 params[i] = (GLint)floatParams[i];
882 }
883 }
884 break;
885 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000886 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
887 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000888 break;
889 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000890 }
891
892 return true;
893}
894
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000895void Program::dirtyAllUniforms()
896{
897 for (unsigned int index = 0; index < mUniforms.size(); index++)
898 {
899 mUniforms[index]->dirty = true;
900 }
901}
902
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000903void Program::dirtyAllSamplers()
904{
905 for (unsigned int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; ++index)
906 {
907 mSamplers[index].dirty = true;
908 }
909}
910
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000911// Applies all the uniforms set for this program object to the Direct3D 9 device
912void Program::applyUniforms()
913{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000914 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000915 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000916 if (mUniformIndex[location].element != 0)
917 {
918 continue;
919 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000920
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000921 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
922
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000923 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000924 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000925 int arraySize = targetUniform->arraySize;
926 GLfloat *f = (GLfloat*)targetUniform->data;
927 GLint *i = (GLint*)targetUniform->data;
928 GLboolean *b = (GLboolean*)targetUniform->data;
929
930 switch (targetUniform->type)
931 {
932 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
933 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
934 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
935 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
936 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
937 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
938 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
939 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
940 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
941 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
942 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
943 case GL_INT: applyUniform1iv(location, arraySize, i); break;
944 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
945 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
946 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
947 default:
948 UNREACHABLE();
949 }
950
951 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000952 }
953 }
954}
955
956// Compiles the HLSL code of the attached shaders into executable binaries
957ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
958{
959 if (!hlsl)
960 {
961 return NULL;
962 }
963
964 ID3DXBuffer *binary = NULL;
965 ID3DXBuffer *errorMessage = NULL;
966
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000967 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, NULL, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000968
969 if (SUCCEEDED(result))
970 {
971 return binary;
972 }
973
974 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
975 {
976 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
977 }
978
979 if (errorMessage)
980 {
981 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000982
daniel@transgaming.com0df16872010-05-12 16:51:08 +0000983 appendToInfoLog("%s\n", message);
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000984 TRACE("\n%s", hlsl);
985 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000986 }
987
988 return NULL;
989}
990
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000991// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
992// Returns the number of used varying registers, or -1 if unsuccesful
993int Program::packVaryings(const Varying *packing[][4])
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000994{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000995 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000996 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000997 int n = VariableRowCount(varying->type) * varying->size;
998 int m = VariableColumnCount(varying->type);
999 bool success = false;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001000
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001001 if (m == 2 || m == 3 || m == 4)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001002 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001003 for (int r = 0; r <= MAX_VARYING_VECTORS - n && !success; r++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001004 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001005 bool available = true;
1006
1007 for (int y = 0; y < n && available; y++)
1008 {
1009 for (int x = 0; x < m && available; x++)
1010 {
1011 if (packing[r + y][x])
1012 {
1013 available = false;
1014 }
1015 }
1016 }
1017
1018 if (available)
1019 {
1020 varying->reg = r;
1021 varying->col = 0;
1022
1023 for (int y = 0; y < n; y++)
1024 {
1025 for (int x = 0; x < m; x++)
1026 {
1027 packing[r + y][x] = &*varying;
1028 }
1029 }
1030
1031 success = true;
1032 }
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001033 }
1034
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001035 if (!success && m == 2)
1036 {
1037 for (int r = MAX_VARYING_VECTORS - n; r >= 0 && !success; r--)
1038 {
1039 bool available = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001040
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001041 for (int y = 0; y < n && available; y++)
1042 {
1043 for (int x = 2; x < 4 && available; x++)
1044 {
1045 if (packing[r + y][x])
1046 {
1047 available = false;
1048 }
1049 }
1050 }
1051
1052 if (available)
1053 {
1054 varying->reg = r;
1055 varying->col = 2;
1056
1057 for (int y = 0; y < n; y++)
1058 {
1059 for (int x = 2; x < 4; x++)
1060 {
1061 packing[r + y][x] = &*varying;
1062 }
1063 }
1064
1065 success = true;
1066 }
1067 }
1068 }
1069 }
1070 else if (m == 1)
1071 {
1072 int space[4] = {0};
1073
1074 for (int y = 0; y < MAX_VARYING_VECTORS; y++)
1075 {
1076 for (int x = 0; x < 4; x++)
1077 {
1078 space[x] += packing[y][x] ? 0 : 1;
1079 }
1080 }
1081
1082 int column = 0;
1083
1084 for (int x = 0; x < 4; x++)
1085 {
1086 if (space[x] > n && space[x] < space[column])
1087 {
1088 column = x;
1089 }
1090 }
1091
1092 if (space[column] > n)
1093 {
1094 for (int r = 0; r < MAX_VARYING_VECTORS; r++)
1095 {
1096 if (!packing[r][column])
1097 {
1098 varying->reg = r;
1099
1100 for (int y = r; y < r + n; y++)
1101 {
1102 packing[y][column] = &*varying;
1103 }
1104
1105 break;
1106 }
1107 }
1108
1109 varying->col = column;
1110
1111 success = true;
1112 }
1113 }
1114 else UNREACHABLE();
1115
1116 if (!success)
1117 {
1118 appendToInfoLog("Could not pack varying %s", varying->name.c_str());
1119
1120 return -1;
1121 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001122 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001123
1124 // Return the number of used registers
1125 int registers = 0;
1126
1127 for (int r = 0; r < MAX_VARYING_VECTORS; r++)
1128 {
1129 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1130 {
1131 registers++;
1132 }
1133 }
1134
1135 return registers;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001136}
1137
1138bool Program::linkVaryings()
1139{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001140 if (mPixelHLSL.empty() || mVertexHLSL.empty())
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001141 {
1142 return false;
1143 }
1144
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001145 const Varying *packing[MAX_VARYING_VECTORS][4] = {NULL};
1146 int registers = packVaryings(packing);
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001147
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001148 if (registers < 0)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001149 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001150 return false;
1151 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001152
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001153 if (registers == MAX_VARYING_VECTORS && mFragmentShader->mUsesFragCoord)
1154 {
1155 appendToInfoLog("No varying registers left to support gl_FragCoord");
1156
1157 return false;
1158 }
1159
1160 for (VaryingList::iterator input = mFragmentShader->varyings.begin(); input != mFragmentShader->varyings.end(); input++)
1161 {
1162 bool matched = false;
1163
1164 for (VaryingList::iterator output = mVertexShader->varyings.begin(); output != mVertexShader->varyings.end(); output++)
1165 {
1166 if (output->name == input->name)
1167 {
1168 if (output->type != input->type || output->size != input->size)
1169 {
1170 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
1171
1172 return false;
1173 }
1174
1175 output->reg = input->reg;
1176 output->col = input->col;
1177
1178 matched = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001179 break;
1180 }
1181 }
1182
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001183 if (!matched)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001184 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001185 appendToInfoLog("Fragment varying varying %s does not match any vertex varying", input->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001186
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001187 return false;
1188 }
1189 }
1190
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001191 mVertexHLSL += "struct VS_INPUT\n"
1192 "{\n";
1193
1194 int semanticIndex = 0;
1195 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1196 {
1197 switch (attribute->type)
1198 {
1199 case GL_FLOAT: mVertexHLSL += " float "; break;
1200 case GL_FLOAT_VEC2: mVertexHLSL += " float2 "; break;
1201 case GL_FLOAT_VEC3: mVertexHLSL += " float3 "; break;
1202 case GL_FLOAT_VEC4: mVertexHLSL += " float4 "; break;
1203 case GL_FLOAT_MAT2: mVertexHLSL += " float2x2 "; break;
1204 case GL_FLOAT_MAT3: mVertexHLSL += " float3x3 "; break;
1205 case GL_FLOAT_MAT4: mVertexHLSL += " float4x4 "; break;
1206 default: UNREACHABLE();
1207 }
1208
1209 mVertexHLSL += decorate(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1210
1211 semanticIndex += VariableRowCount(attribute->type);
1212 }
1213
1214 mVertexHLSL += "};\n"
1215 "\n"
1216 "struct VS_OUTPUT\n"
1217 "{\n"
1218 " float4 gl_Position : POSITION;\n";
1219
1220 for (int r = 0; r < registers; r++)
1221 {
1222 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1223
1224 mVertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : TEXCOORD" + str(r) + ";\n";
1225 }
1226
1227 if (mFragmentShader->mUsesFragCoord)
1228 {
1229 mVertexHLSL += " float4 gl_FragCoord : TEXCOORD" + str(registers) + ";\n";
1230 }
1231
1232 mVertexHLSL += "};\n"
1233 "\n"
1234 "VS_OUTPUT main(VS_INPUT input)\n"
1235 "{\n";
1236
1237 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1238 {
1239 mVertexHLSL += " " + decorate(attribute->name) + " = ";
1240
1241 if (VariableRowCount(attribute->type) > 1) // Matrix
1242 {
1243 mVertexHLSL += "transpose";
1244 }
1245
1246 mVertexHLSL += "(input." + decorate(attribute->name) + ");\n";
1247 }
1248
1249 mVertexHLSL += "\n"
1250 " gl_main();\n"
1251 "\n"
1252 " VS_OUTPUT output;\n"
1253 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
1254 " output.gl_Position.y = -(gl_Position.y - dx_HalfPixelSize.y * gl_Position.w);\n"
1255 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1256 " output.gl_Position.w = gl_Position.w;\n";
1257
1258 if (mFragmentShader->mUsesFragCoord)
1259 {
1260 mVertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1261 }
1262
1263 for (VaryingList::iterator varying = mVertexShader->varyings.begin(); varying != mVertexShader->varyings.end(); varying++)
1264 {
1265 if (varying->reg >= 0)
1266 {
1267 for (int i = 0; i < varying->size; i++)
1268 {
1269 int rows = VariableRowCount(varying->type);
1270
1271 for (int j = 0; j < rows; j++)
1272 {
1273 int r = varying->reg + i * rows + j;
1274 mVertexHLSL += " output.v" + str(r);
1275
1276 bool sharedRegister = false; // Register used by multiple varyings
1277
1278 for (int x = 0; x < 4; x++)
1279 {
1280 if (packing[r][x] && packing[r][x] != packing[r][0])
1281 {
1282 sharedRegister = true;
1283 break;
1284 }
1285 }
1286
1287 if(sharedRegister)
1288 {
1289 mVertexHLSL += ".";
1290
1291 for (int x = 0; x < 4; x++)
1292 {
1293 if (packing[r][x] == &*varying)
1294 {
1295 switch(x)
1296 {
1297 case 0: mVertexHLSL += "x"; break;
1298 case 1: mVertexHLSL += "y"; break;
1299 case 2: mVertexHLSL += "z"; break;
1300 case 3: mVertexHLSL += "w"; break;
1301 }
1302 }
1303 }
1304 }
1305
1306 mVertexHLSL += " = " + varying->name;
1307
1308 if (varying->array)
1309 {
1310 mVertexHLSL += "[" + str(i) + "]";
1311 }
1312
1313 if (rows > 1)
1314 {
1315 mVertexHLSL += "[" + str(j) + "]";
1316 }
1317
1318 mVertexHLSL += ";\n";
1319 }
1320 }
1321 }
1322 }
1323
1324 mVertexHLSL += "\n"
1325 " return output;\n"
1326 "}\n";
1327
1328 mPixelHLSL += "struct PS_INPUT\n"
1329 "{\n";
1330
1331 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1332 {
1333 if (varying->reg >= 0)
1334 {
1335 for (int i = 0; i < varying->size; i++)
1336 {
1337 int rows = VariableRowCount(varying->type);
1338 for (int j = 0; j < rows; j++)
1339 {
1340 std::string n = str(varying->reg + i * rows + j);
1341 mPixelHLSL += " float4 v" + n + " : TEXCOORD" + n + ";\n";
1342 }
1343 }
1344 }
1345 else UNREACHABLE();
1346 }
1347
1348 if (mFragmentShader->mUsesFragCoord)
1349 {
1350 mPixelHLSL += " float4 gl_FragCoord : TEXCOORD" + str(registers) + ";\n";
1351 }
1352
1353 if (mFragmentShader->mUsesFrontFacing)
1354 {
1355 mPixelHLSL += " float vFace : VFACE;\n";
1356 }
1357
1358 mPixelHLSL += "};\n"
1359 "\n"
1360 "struct PS_OUTPUT\n"
1361 "{\n"
1362 " float4 gl_Color[1] : COLOR;\n"
1363 "};\n"
1364 "\n"
1365 "PS_OUTPUT main(PS_INPUT input)\n"
1366 "{\n";
1367
1368 if (mFragmentShader->mUsesFragCoord)
1369 {
1370 mPixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n"
1371 " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Window.x + dx_Window.z;\n"
1372 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Window.y + dx_Window.w;\n"
1373 " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
1374 " gl_FragCoord.w = rhw;\n";
1375 }
1376
1377 if (mFragmentShader->mUsesFrontFacing)
1378 {
1379 mPixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1380 }
1381
1382 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1383 {
1384 if (varying->reg >= 0)
1385 {
1386 for (int i = 0; i < varying->size; i++)
1387 {
1388 int rows = VariableRowCount(varying->type);
1389 for (int j = 0; j < rows; j++)
1390 {
1391 std::string n = str(varying->reg + i * rows + j);
1392 mPixelHLSL += " " + varying->name;
1393
1394 if (varying->array)
1395 {
1396 mPixelHLSL += "[" + str(i) + "]";
1397 }
1398
1399 if (rows > 1)
1400 {
1401 mPixelHLSL += "[" + str(j) + "]";
1402 }
1403
1404 mPixelHLSL += " = input.v" + n + ";\n";
1405 }
1406 }
1407 }
1408 else UNREACHABLE();
1409 }
1410
1411 mPixelHLSL += "\n"
1412 " gl_main();\n"
1413 "\n"
1414 " PS_OUTPUT output;\n"
1415 " output.gl_Color[0] = gl_Color[0];\n"
1416 "\n"
1417 " return output;\n"
1418 "}\n";
1419
1420 TRACE("\n%s", mPixelHLSL.c_str());
1421 TRACE("\n%s", mVertexHLSL.c_str());
1422
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001423 return true;
1424}
1425
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001426// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1427// compiling them into binaries, determining the attribute mappings, and collecting
1428// a list of uniforms
1429void Program::link()
1430{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001431 unlink();
1432
1433 if (!mFragmentShader || !mFragmentShader->isCompiled())
1434 {
1435 return;
1436 }
1437
1438 if (!mVertexShader || !mVertexShader->isCompiled())
1439 {
1440 return;
1441 }
1442
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001443 Context *context = getContext();
1444 const char *vertexProfile = context->getVertexShaderProfile();
1445 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +00001446
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001447 mPixelHLSL = mFragmentShader->getHLSL();
1448 mVertexHLSL = mVertexShader->getHLSL();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001449
1450 if (!linkVaryings())
1451 {
1452 return;
1453 }
1454
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001455 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1456 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001457
1458 if (vertexBinary && pixelBinary)
1459 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001460 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001461 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1462 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1463
1464 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1465 {
1466 return error(GL_OUT_OF_MEMORY);
1467 }
1468
1469 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001470
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001471 vertexBinary->Release();
1472 pixelBinary->Release();
1473 vertexBinary = NULL;
1474 pixelBinary = NULL;
1475
1476 if (mVertexExecutable && mPixelExecutable)
1477 {
1478 if (!linkAttributes())
1479 {
1480 return;
1481 }
1482
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001483 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001484 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001485 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001486 }
1487
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001488 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001489 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001490 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001491 }
1492
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001493 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001494 }
1495 }
1496}
1497
1498// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1499bool Program::linkAttributes()
1500{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001501 unsigned int usedLocations = 0;
1502
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001503 // Link attributes that have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001504 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001505 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001506 int location = getAttributeBinding(attribute->name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001507
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001508 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001509 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001510 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001511 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001512 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001513 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001514
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001515 mLinkedAttribute[location] = *attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001516
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001517 int rows = VariableRowCount(attribute->type);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001518
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001519 if (rows + location > MAX_VERTEX_ATTRIBS)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001520 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001521 appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001522
1523 return false;
1524 }
1525
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001526 for (int i = 0; i < rows; i++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001527 {
1528 usedLocations |= 1 << (location + i);
1529 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001530 }
1531 }
1532
1533 // Link attributes that don't have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001534 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001535 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001536 int location = getAttributeBinding(attribute->name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001537
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001538 if (location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001539 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001540 int rows = VariableRowCount(attribute->type);
1541 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001542
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001543 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001544 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001545 appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001546
1547 return false; // Fail to link
1548 }
1549
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001550 mLinkedAttribute[availableIndex] = *attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001551 }
1552 }
1553
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001554 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001555 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001556 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001557 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001558
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001559 for (int r = 0; r < rows; r++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001560 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001561 mSemanticIndex[attributeIndex++] = index++;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001562 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001563 }
1564
1565 return true;
1566}
1567
daniel@transgaming.com85423182010-04-22 13:35:27 +00001568int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001569{
1570 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1571 {
1572 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1573 {
1574 return location;
1575 }
1576 }
1577
1578 return -1;
1579}
1580
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001581bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1582{
1583 D3DXCONSTANTTABLE_DESC constantTableDescription;
1584 D3DXCONSTANT_DESC constantDescription;
1585 UINT descriptionCount = 1;
1586
1587 constantTable->GetDesc(&constantTableDescription);
1588
1589 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1590 {
1591 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1592 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1593
1594 if (!defineUniform(constantHandle, constantDescription))
1595 {
1596 return false;
1597 }
1598 }
1599
1600 return true;
1601}
1602
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001603// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001604// Returns true if succesful (uniform not already defined)
1605bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1606{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001607 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1608 {
1609 unsigned int samplerIndex = constantDescription.RegisterIndex;
1610
1611 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1612
1613 mSamplers[samplerIndex].active = true;
1614 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1615 mSamplers[samplerIndex].logicalTextureUnit = 0;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001616 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001617 }
1618
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001619 switch(constantDescription.Class)
1620 {
1621 case D3DXPC_STRUCT:
1622 {
1623 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1624 {
1625 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1626
1627 D3DXCONSTANT_DESC fieldDescription;
1628 UINT descriptionCount = 1;
1629
1630 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1631
1632 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1633 {
1634 return false;
1635 }
1636 }
1637
1638 return true;
1639 }
1640 case D3DXPC_SCALAR:
1641 case D3DXPC_VECTOR:
1642 case D3DXPC_MATRIX_COLUMNS:
1643 case D3DXPC_OBJECT:
1644 return defineUniform(constantDescription, name + constantDescription.Name);
1645 default:
1646 UNREACHABLE();
1647 return false;
1648 }
1649}
1650
1651bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1652{
1653 Uniform *uniform = createUniform(constantDescription, name);
1654
1655 if(!uniform)
1656 {
1657 return false;
1658 }
1659
1660 // Check if already defined
1661 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001662 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001663
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001664 if (location >= 0)
1665 {
1666 delete uniform;
1667
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001668 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001669 {
1670 return false;
1671 }
1672 else
1673 {
1674 return true;
1675 }
1676 }
1677
1678 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001679 unsigned int uniformIndex = mUniforms.size() - 1;
1680
1681 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1682 {
1683 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1684 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001685
1686 return true;
1687}
1688
1689Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001690{
1691 if (constantDescription.Rows == 1) // Vectors and scalars
1692 {
1693 switch (constantDescription.Type)
1694 {
1695 case D3DXPT_SAMPLER2D:
1696 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001697 switch (constantDescription.Columns)
1698 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001699 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001700 default: UNREACHABLE();
1701 }
1702 break;
1703 case D3DXPT_BOOL:
1704 switch (constantDescription.Columns)
1705 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001706 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1707 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1708 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1709 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001710 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001711 }
1712 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001713 case D3DXPT_INT:
1714 switch (constantDescription.Columns)
1715 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001716 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1717 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1718 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1719 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001720 default: UNREACHABLE();
1721 }
1722 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001723 case D3DXPT_FLOAT:
1724 switch (constantDescription.Columns)
1725 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001726 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1727 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1728 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1729 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001730 default: UNREACHABLE();
1731 }
1732 break;
1733 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001734 UNREACHABLE();
1735 }
1736 }
1737 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1738 {
1739 switch (constantDescription.Type)
1740 {
1741 case D3DXPT_FLOAT:
1742 switch (constantDescription.Rows)
1743 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001744 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1745 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1746 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001747 default: UNREACHABLE();
1748 }
1749 break;
1750 default: UNREACHABLE();
1751 }
1752 }
1753 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001754
1755 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001756}
1757
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001758// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001759std::string Program::decorate(const std::string &string)
1760{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001761 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001762 {
1763 return "_" + string;
1764 }
1765 else
1766 {
1767 return string;
1768 }
1769}
1770
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001771std::string Program::undecorate(const std::string &string)
1772{
1773 if (string.substr(0, 1) == "_")
1774 {
1775 return string.substr(1);
1776 }
1777 else
1778 {
1779 return string;
1780 }
1781}
1782
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001783bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1784{
1785 BOOL *vector = new BOOL[count];
1786 for (int i = 0; i < count; i++)
1787 {
1788 if (v[i] == GL_FALSE)
1789 vector[i] = 0;
1790 else
1791 vector[i] = 1;
1792 }
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.comf4a0c8e2010-04-13 03:26:01 +00001798 IDirect3DDevice9 *device = getDevice();
1799
1800 if (constantPS)
1801 {
1802 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1803 }
1804
1805 if (constantVS)
1806 {
1807 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1808 }
1809
1810 delete [] vector;
1811
1812 return true;
1813}
1814
1815bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1816{
1817 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1818
1819 for (int i = 0; i < count; i++)
1820 {
1821 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1822 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1823
1824 v += 2;
1825 }
1826
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001827 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1828
1829 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1830 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001831 IDirect3DDevice9 *device = getDevice();
1832
1833 if (constantPS)
1834 {
1835 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1836 }
1837
1838 if (constantVS)
1839 {
1840 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1841 }
1842
1843 delete[] vector;
1844
1845 return true;
1846}
1847
1848bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1849{
1850 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1851
1852 for (int i = 0; i < count; i++)
1853 {
1854 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1855 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1856 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1857
1858 v += 3;
1859 }
1860
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001861 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1862
1863 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1864 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001865 IDirect3DDevice9 *device = getDevice();
1866
1867 if (constantPS)
1868 {
1869 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1870 }
1871
1872 if (constantVS)
1873 {
1874 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1875 }
1876
1877 delete[] vector;
1878
1879 return true;
1880}
1881
1882bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1883{
1884 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1885
1886 for (int i = 0; i < count; i++)
1887 {
1888 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1889 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1890 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1891 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1892
1893 v += 3;
1894 }
1895
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001896 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1897
1898 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1899 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001900 IDirect3DDevice9 *device = getDevice();
1901
1902 if (constantPS)
1903 {
1904 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1905 }
1906
1907 if (constantVS)
1908 {
1909 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1910 }
1911
1912 delete [] vector;
1913
1914 return true;
1915}
1916
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001917bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1918{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001919 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1920
1921 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1922 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001923 IDirect3DDevice9 *device = getDevice();
1924
1925 if (constantPS)
1926 {
1927 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1928 }
1929
1930 if (constantVS)
1931 {
1932 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1933 }
1934
1935 return true;
1936}
1937
1938bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1939{
1940 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1941
1942 for (int i = 0; i < count; i++)
1943 {
1944 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1945
1946 v += 2;
1947 }
1948
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001949 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1950
1951 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1952 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001953 IDirect3DDevice9 *device = getDevice();
1954
1955 if (constantPS)
1956 {
1957 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1958 }
1959
1960 if (constantVS)
1961 {
1962 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1963 }
1964
1965 delete[] vector;
1966
1967 return true;
1968}
1969
1970bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1971{
1972 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1973
1974 for (int i = 0; i < count; i++)
1975 {
1976 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1977
1978 v += 3;
1979 }
1980
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001981 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1982
1983 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1984 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001985 IDirect3DDevice9 *device = getDevice();
1986
1987 if (constantPS)
1988 {
1989 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1990 }
1991
1992 if (constantVS)
1993 {
1994 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1995 }
1996
1997 delete[] vector;
1998
1999 return true;
2000}
2001
2002bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
2003{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002004 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2005
2006 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2007 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002008 IDirect3DDevice9 *device = getDevice();
2009
2010 if (constantPS)
2011 {
2012 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
2013 }
2014
2015 if (constantVS)
2016 {
2017 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
2018 }
2019
2020 return true;
2021}
2022
2023bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
2024{
2025 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2026
2027 for (int i = 0; i < count; i++)
2028 {
2029 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
2030 value[1], value[3], 0, 0,
2031 0, 0, 1, 0,
2032 0, 0, 0, 1);
2033
2034 value += 4;
2035 }
2036
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002037 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2038
2039 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2040 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002041 IDirect3DDevice9 *device = getDevice();
2042
2043 if (constantPS)
2044 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002045 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002046 }
2047
2048 if (constantVS)
2049 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002050 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002051 }
2052
2053 delete[] matrix;
2054
2055 return true;
2056}
2057
2058bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
2059{
2060 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2061
2062 for (int i = 0; i < count; i++)
2063 {
2064 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
2065 value[1], value[4], value[7], 0,
2066 value[2], value[5], value[8], 0,
2067 0, 0, 0, 1);
2068
2069 value += 9;
2070 }
2071
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002072 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2073
2074 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2075 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002076 IDirect3DDevice9 *device = getDevice();
2077
2078 if (constantPS)
2079 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002080 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002081 }
2082
2083 if (constantVS)
2084 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002085 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002086 }
2087
2088 delete[] matrix;
2089
2090 return true;
2091}
2092
2093bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
2094{
2095 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2096
2097 for (int i = 0; i < count; i++)
2098 {
2099 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
2100 value[1], value[5], value[9], value[13],
2101 value[2], value[6], value[10], value[14],
2102 value[3], value[7], value[11], value[15]);
2103
2104 value += 16;
2105 }
2106
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002107 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2108
2109 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2110 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002111 IDirect3DDevice9 *device = getDevice();
2112
2113 if (constantPS)
2114 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002115 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002116 }
2117
2118 if (constantVS)
2119 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002120 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002121 }
2122
2123 delete[] matrix;
2124
2125 return true;
2126}
2127
2128bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
2129{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002130 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2131
2132 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2133 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002134 IDirect3DDevice9 *device = getDevice();
2135
2136 if (constantPS)
2137 {
2138 D3DXCONSTANT_DESC constantDescription;
2139 UINT descriptionCount = 1;
2140 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
2141
daniel@transgaming.com2884b782010-03-08 21:30:48 +00002142 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002143 {
2144 return false;
2145 }
2146
2147 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2148 {
2149 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
2150
2151 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
2152 {
2153 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002154
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002155 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002156 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002157 ASSERT(mSamplers[samplerIndex].active);
2158 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
2159 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002160 }
2161 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002162
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002163 return true;
2164 }
2165 }
2166
2167 if (constantPS)
2168 {
2169 mConstantTablePS->SetIntArray(device, constantPS, v, count);
2170 }
2171
2172 if (constantVS)
2173 {
2174 mConstantTableVS->SetIntArray(device, constantVS, v, count);
2175 }
2176
2177 return true;
2178}
2179
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002180bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
2181{
2182 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2183
2184 for (int i = 0; i < count; i++)
2185 {
2186 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2187
2188 v += 2;
2189 }
2190
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002191 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2192
2193 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2194 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002195 IDirect3DDevice9 *device = getDevice();
2196
2197 if (constantPS)
2198 {
2199 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2200 }
2201
2202 if (constantVS)
2203 {
2204 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2205 }
2206
2207 delete[] vector;
2208
2209 return true;
2210}
2211
2212bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
2213{
2214 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2215
2216 for (int i = 0; i < count; i++)
2217 {
2218 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2219
2220 v += 3;
2221 }
2222
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002223 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2224
2225 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2226 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002227 IDirect3DDevice9 *device = getDevice();
2228
2229 if (constantPS)
2230 {
2231 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2232 }
2233
2234 if (constantVS)
2235 {
2236 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2237 }
2238
2239 delete[] vector;
2240
2241 return true;
2242}
2243
2244bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
2245{
2246 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2247
2248 for (int i = 0; i < count; i++)
2249 {
2250 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2251
2252 v += 4;
2253 }
2254
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002255 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2256
2257 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2258 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002259 IDirect3DDevice9 *device = getDevice();
2260
2261 if (constantPS)
2262 {
2263 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2264 }
2265
2266 if (constantVS)
2267 {
2268 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2269 }
2270
2271 delete [] vector;
2272
2273 return true;
2274}
2275
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002276void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002277{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002278 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002279 {
2280 return;
2281 }
2282
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002283 char info[1024];
2284
2285 va_list vararg;
2286 va_start(vararg, format);
2287 vsnprintf(info, sizeof(info), format, vararg);
2288 va_end(vararg);
2289
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002290 size_t infoLength = strlen(info);
2291
2292 if (!mInfoLog)
2293 {
2294 mInfoLog = new char[infoLength + 1];
2295 strcpy(mInfoLog, info);
2296 }
2297 else
2298 {
2299 size_t logLength = strlen(mInfoLog);
2300 char *newLog = new char[logLength + infoLength + 1];
2301 strcpy(newLog, mInfoLog);
2302 strcpy(newLog + logLength, info);
2303
2304 delete[] mInfoLog;
2305 mInfoLog = newLog;
2306 }
2307}
2308
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002309void Program::resetInfoLog()
2310{
2311 if (mInfoLog)
2312 {
2313 delete [] mInfoLog;
2314 }
2315}
2316
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002317// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
2318void Program::unlink(bool destroy)
2319{
2320 if (destroy) // Object being destructed
2321 {
2322 if (mFragmentShader)
2323 {
2324 mFragmentShader->detach();
2325 mFragmentShader = NULL;
2326 }
2327
2328 if (mVertexShader)
2329 {
2330 mVertexShader->detach();
2331 mVertexShader = NULL;
2332 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002333 }
2334
2335 if (mPixelExecutable)
2336 {
2337 mPixelExecutable->Release();
2338 mPixelExecutable = NULL;
2339 }
2340
2341 if (mVertexExecutable)
2342 {
2343 mVertexExecutable->Release();
2344 mVertexExecutable = NULL;
2345 }
2346
2347 if (mConstantTablePS)
2348 {
2349 mConstantTablePS->Release();
2350 mConstantTablePS = NULL;
2351 }
2352
2353 if (mConstantTableVS)
2354 {
2355 mConstantTableVS->Release();
2356 mConstantTableVS = NULL;
2357 }
2358
2359 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2360 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002361 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002362 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002363 }
2364
2365 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2366 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00002367 mSamplers[index].active = false;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00002368 mSamplers[index].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002369 }
2370
2371 while (!mUniforms.empty())
2372 {
2373 delete mUniforms.back();
2374 mUniforms.pop_back();
2375 }
2376
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002377 mUniformIndex.clear();
2378
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002379 mPixelHLSL.clear();
2380 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002381
2382 delete[] mInfoLog;
2383 mInfoLog = NULL;
2384
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002385 mLinked = false;
2386}
2387
2388bool Program::isLinked()
2389{
2390 return mLinked;
2391}
2392
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002393bool Program::isValidated() const
2394{
2395 return mValidated;
2396}
2397
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002398unsigned int Program::getSerial() const
2399{
2400 return mSerial;
2401}
2402
2403unsigned int Program::issueSerial()
2404{
2405 return mCurrentSerial++;
2406}
2407
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002408int Program::getInfoLogLength() const
2409{
2410 if (!mInfoLog)
2411 {
2412 return 0;
2413 }
2414 else
2415 {
2416 return strlen(mInfoLog) + 1;
2417 }
2418}
2419
2420void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2421{
2422 int index = 0;
2423
2424 if (mInfoLog)
2425 {
2426 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2427 {
2428 infoLog[index] = mInfoLog[index];
2429 index++;
2430 }
2431 }
2432
2433 if (bufSize)
2434 {
2435 infoLog[index] = '\0';
2436 }
2437
2438 if (length)
2439 {
2440 *length = index;
2441 }
2442}
2443
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002444void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2445{
2446 int total = 0;
2447
2448 if (mVertexShader)
2449 {
2450 if (total < maxCount)
2451 {
2452 shaders[total] = mVertexShader->getHandle();
2453 }
2454
2455 total++;
2456 }
2457
2458 if (mFragmentShader)
2459 {
2460 if (total < maxCount)
2461 {
2462 shaders[total] = mFragmentShader->getHandle();
2463 }
2464
2465 total++;
2466 }
2467
2468 if (count)
2469 {
2470 *count = total;
2471 }
2472}
2473
daniel@transgaming.com85423182010-04-22 13:35:27 +00002474void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2475{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002476 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002477 for (unsigned int i = 0; i < index; i++)
2478 {
2479 do
2480 {
2481 attribute++;
2482
2483 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2484 }
2485 while (mLinkedAttribute[attribute].name.empty());
2486 }
2487
2488 if (bufsize > 0)
2489 {
2490 const char *string = mLinkedAttribute[attribute].name.c_str();
2491
2492 strncpy(name, string, bufsize);
2493 name[bufsize - 1] = '\0';
2494
2495 if (length)
2496 {
2497 *length = strlen(name);
2498 }
2499 }
2500
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002501 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002502
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002503 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002504}
2505
2506GLint Program::getActiveAttributeCount()
2507{
2508 int count = 0;
2509
2510 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2511 {
2512 if (!mLinkedAttribute[attributeIndex].name.empty())
2513 {
2514 count++;
2515 }
2516 }
2517
2518 return count;
2519}
2520
2521GLint Program::getActiveAttributeMaxLength()
2522{
2523 int maxLength = 0;
2524
2525 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2526 {
2527 if (!mLinkedAttribute[attributeIndex].name.empty())
2528 {
2529 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2530 }
2531 }
2532
2533 return maxLength;
2534}
2535
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002536void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2537{
2538 unsigned int uniform = 0;
2539 for (unsigned int i = 0; i < index; i++)
2540 {
2541 do
2542 {
2543 uniform++;
2544
2545 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2546 }
2547 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2548 }
2549
2550 if (bufsize > 0)
2551 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002552 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002553
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002554 if (mUniforms[uniform]->arraySize != 1)
2555 {
2556 string += "[0]";
2557 }
2558
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002559 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002560 name[bufsize - 1] = '\0';
2561
2562 if (length)
2563 {
2564 *length = strlen(name);
2565 }
2566 }
2567
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002568 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002569
2570 *type = mUniforms[uniform]->type;
2571}
2572
2573GLint Program::getActiveUniformCount()
2574{
2575 int count = 0;
2576
2577 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2578 {
2579 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2580 {
2581 count++;
2582 }
2583 }
2584
2585 return count;
2586}
2587
2588GLint Program::getActiveUniformMaxLength()
2589{
2590 int maxLength = 0;
2591
2592 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2593 {
2594 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2595 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002596 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002597 }
2598 }
2599
2600 return maxLength;
2601}
2602
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002603void Program::flagForDeletion()
2604{
2605 mDeleteStatus = true;
2606}
2607
2608bool Program::isFlaggedForDeletion() const
2609{
2610 return mDeleteStatus;
2611}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002612
2613void Program::validate()
2614{
2615 resetInfoLog();
2616
2617 if (!isLinked())
2618 {
2619 appendToInfoLog("Program has not been successfully linked.");
2620 mValidated = false;
2621 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002622 else
2623 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002624 applyUniforms();
2625 if (!validateSamplers())
2626 {
2627 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2628 mValidated = false;
2629 }
2630 else
2631 {
2632 mValidated = true;
2633 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002634 }
2635}
2636
2637bool Program::validateSamplers() const
2638{
2639 // if any two active samplers in a program are of different types, but refer to the same
2640 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2641 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2642 std::map<int, SamplerType> samplerMap;
2643 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2644 {
2645 if (mSamplers[i].active)
2646 {
2647 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2648 {
2649 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2650 return false;
2651 }
2652 else
2653 {
2654 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2655 }
2656 }
2657 }
2658
2659 return true;
2660}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002661}