blob: a32bc9faa3712a05878f0fe61504d5833996d3cb [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.com2d84df02010-05-14 17:31:13 +000035 handlesSet = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000036}
37
38Uniform::~Uniform()
39{
40 delete[] data;
41}
42
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +000043UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
44 : name(name), element(element), index(index)
45{
46}
47
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000048Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000049{
50 mFragmentShader = NULL;
51 mVertexShader = NULL;
52
53 mPixelExecutable = NULL;
54 mVertexExecutable = NULL;
55 mConstantTablePS = NULL;
56 mConstantTableVS = NULL;
57
daniel@transgaming.comcba50572010-03-28 19:36:09 +000058 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +000059 mValidated = false;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000060
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000061 unlink();
62
63 mDeleteStatus = false;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000064
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000065 mRefCount = 0;
66
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000067 mSerial = issueSerial();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000068}
69
70Program::~Program()
71{
72 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000073
74 if (mVertexShader != NULL)
75 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000076 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000077 }
78
79 if (mFragmentShader != NULL)
80 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000081 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000082 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000083}
84
85bool Program::attachShader(Shader *shader)
86{
87 if (shader->getType() == GL_VERTEX_SHADER)
88 {
89 if (mVertexShader)
90 {
91 return false;
92 }
93
94 mVertexShader = (VertexShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000095 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000096 }
97 else if (shader->getType() == GL_FRAGMENT_SHADER)
98 {
99 if (mFragmentShader)
100 {
101 return false;
102 }
103
104 mFragmentShader = (FragmentShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000105 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000106 }
107 else UNREACHABLE();
108
109 return true;
110}
111
112bool Program::detachShader(Shader *shader)
113{
114 if (shader->getType() == GL_VERTEX_SHADER)
115 {
116 if (mVertexShader != shader)
117 {
118 return false;
119 }
120
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000121 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000122 mVertexShader = NULL;
123 }
124 else if (shader->getType() == GL_FRAGMENT_SHADER)
125 {
126 if (mFragmentShader != shader)
127 {
128 return false;
129 }
130
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000131 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000132 mFragmentShader = NULL;
133 }
134 else UNREACHABLE();
135
136 unlink();
137
138 return true;
139}
140
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000141int Program::getAttachedShadersCount() const
142{
143 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
144}
145
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000146IDirect3DPixelShader9 *Program::getPixelShader()
147{
148 return mPixelExecutable;
149}
150
151IDirect3DVertexShader9 *Program::getVertexShader()
152{
153 return mVertexExecutable;
154}
155
156void Program::bindAttributeLocation(GLuint index, const char *name)
157{
158 if (index < MAX_VERTEX_ATTRIBS)
159 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000160 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
161 {
162 mAttributeBinding[i].erase(name);
163 }
164
165 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000166 }
167}
168
169GLuint Program::getAttributeLocation(const char *name)
170{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000171 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000172 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000173 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000175 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000176 {
177 return index;
178 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179 }
180 }
181
182 return -1;
183}
184
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000185int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000186{
187 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
188 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000189 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000190 }
191
192 return -1;
193}
194
195// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
196// index referenced in the compiled HLSL shader
197GLint Program::getSamplerMapping(unsigned int samplerIndex)
198{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000199 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
200
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000201 GLint logicalTextureUnit = -1;
202
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000203 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000204 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000205 logicalTextureUnit = mSamplers[samplerIndex].logicalTextureUnit;
206 }
207
208 if (logicalTextureUnit < MAX_TEXTURE_IMAGE_UNITS)
209 {
210 return logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000211 }
212
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000213 return -1;
214}
215
216SamplerType Program::getSamplerType(unsigned int samplerIndex)
217{
218 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
219 assert(mSamplers[samplerIndex].active);
220
221 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000222}
223
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000224bool Program::isSamplerDirty(unsigned int samplerIndex) const
225{
226 if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]))
227 {
228 return mSamplers[samplerIndex].dirty;
229 }
230 else UNREACHABLE();
231
232 return false;
233}
234
235void Program::setSamplerDirty(unsigned int samplerIndex, bool dirty)
236{
237 if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]))
238 {
239 mSamplers[samplerIndex].dirty = dirty;
240 }
241 else UNREACHABLE();
242}
243
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000244GLint Program::getUniformLocation(const char *name, bool decorated)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000245{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000246 std::string nameStr(name);
247 int subscript = 0;
248 size_t beginB = nameStr.find('[');
249 size_t endB = nameStr.find(']');
250 if (beginB != std::string::npos && endB != std::string::npos)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000251 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000252 std::string subscrStr = nameStr.substr(beginB + 1, beginB - endB - 1);
253 nameStr.erase(beginB);
254 subscript = atoi(subscrStr.c_str());
255 }
256
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000257 if (!decorated)
258 {
259 nameStr = decorate(nameStr);
260 }
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000261
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000262 unsigned int numUniforms = mUniformIndex.size();
263 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000264 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000265 if (mUniformIndex[location].name == nameStr &&
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000266 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000267 {
268 return location;
269 }
270 }
271
272 return -1;
273}
274
275bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
276{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000277 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000278 {
279 return false;
280 }
281
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000282 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000283 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000284
285 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000286 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000287 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000288
289 if (arraySize == 1 && count > 1)
290 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
291
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000292 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000293
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000294 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
295 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000296 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000297 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000298 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000299 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000300
301 if (arraySize == 1 && count > 1)
302 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000303
304 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000305 GLboolean *boolParams = new GLboolean[count];
306
307 for (int i = 0; i < count; ++i)
308 {
309 if (v[i] == 0.0f)
310 {
311 boolParams[i] = GL_FALSE;
312 }
313 else
314 {
315 boolParams[i] = GL_TRUE;
316 }
317 }
318
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000319 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
320 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000321
322 delete [] boolParams;
323 }
324 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000325 {
326 return false;
327 }
328
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000329 return true;
330}
331
332bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
333{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000334 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000335 {
336 return false;
337 }
338
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000339 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000340 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000341
342 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000343 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000344 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000345
346 if (arraySize == 1 && count > 1)
347 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
348
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000349 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000350
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000351 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
352 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000353 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000354 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000355 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000356 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000357
358 if (arraySize == 1 && count > 1)
359 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
360
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000361 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
362
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000363 GLboolean *boolParams = new GLboolean[count * 2];
364
365 for (int i = 0; i < count * 2; ++i)
366 {
367 if (v[i] == 0.0f)
368 {
369 boolParams[i] = GL_FALSE;
370 }
371 else
372 {
373 boolParams[i] = GL_TRUE;
374 }
375 }
376
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000377 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
378 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000379
380 delete [] boolParams;
381 }
382 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000383 {
384 return false;
385 }
386
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000387 return true;
388}
389
390bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
391{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000392 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000393 {
394 return false;
395 }
396
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000397 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000398 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000399
400 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000401 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000402 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000403
404 if (arraySize == 1 && count > 1)
405 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
406
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000407 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000408
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000409 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
410 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000411 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000412 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000413 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000414 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000415
416 if (arraySize == 1 && count > 1)
417 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
418
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000419 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000420 GLboolean *boolParams = new GLboolean[count * 3];
421
422 for (int i = 0; i < count * 3; ++i)
423 {
424 if (v[i] == 0.0f)
425 {
426 boolParams[i] = GL_FALSE;
427 }
428 else
429 {
430 boolParams[i] = GL_TRUE;
431 }
432 }
433
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000434 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
435 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000436
437 delete [] boolParams;
438 }
439 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000440 {
441 return false;
442 }
443
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000444 return true;
445}
446
447bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
448{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000449 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000450 {
451 return false;
452 }
453
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000454 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000455 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000456
457 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000458 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000459 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000460
461 if (arraySize == 1 && count > 1)
462 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
463
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000464 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000465
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000466 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
467 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000468 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000469 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000470 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000471 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000472
473 if (arraySize == 1 && count > 1)
474 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
475
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000476 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000477 GLboolean *boolParams = new GLboolean[count * 4];
478
479 for (int i = 0; i < count * 4; ++i)
480 {
481 if (v[i] == 0.0f)
482 {
483 boolParams[i] = GL_FALSE;
484 }
485 else
486 {
487 boolParams[i] = GL_TRUE;
488 }
489 }
490
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000491 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
492 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000493
494 delete [] boolParams;
495 }
496 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000497 {
498 return false;
499 }
500
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000501 return true;
502}
503
504bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
505{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000506 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000507 {
508 return false;
509 }
510
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000511 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000512 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000513
514 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000515 {
516 return false;
517 }
518
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000519 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000520
521 if (arraySize == 1 && count > 1)
522 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
523
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000524 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000525
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000526 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
527 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000528
529 return true;
530}
531
532bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
533{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000534 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000535 {
536 return false;
537 }
538
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000539 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000540 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000541
542 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000543 {
544 return false;
545 }
546
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000547 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000548
549 if (arraySize == 1 && count > 1)
550 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
551
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000552 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000553
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000554 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
555 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000556
557 return true;
558}
559
560bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
561{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000562 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000563 {
564 return false;
565 }
566
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000567 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000568 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000569
570 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000571 {
572 return false;
573 }
574
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000575 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000576
577 if (arraySize == 1 && count > 1)
578 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
579
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000580 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000581
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000582 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
583 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000584
585 return true;
586}
587
588bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
589{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000590 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000591 {
592 return false;
593 }
594
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000595 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000596 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000597
598 if (targetUniform->type == GL_INT)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000599 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000600 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000601
602 if (arraySize == 1 && count > 1)
603 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
604
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000605 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000606
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000607 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
608 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000609 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000610 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000611 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000612 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000613
614 if (arraySize == 1 && count > 1)
615 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
616
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000617 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000618 GLboolean *boolParams = new GLboolean[count];
619
620 for (int i = 0; i < count; ++i)
621 {
622 if (v[i] == 0)
623 {
624 boolParams[i] = GL_FALSE;
625 }
626 else
627 {
628 boolParams[i] = GL_TRUE;
629 }
630 }
631
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000632 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
633 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000634
635 delete [] boolParams;
636 }
637 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000638 {
639 return false;
640 }
641
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000642 return true;
643}
644
645bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
646{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000647 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000648 {
649 return false;
650 }
651
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000652 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000653 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000654
655 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000656 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000657 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000658
659 if (arraySize == 1 && count > 1)
660 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
661
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000662 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000663
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000664 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
665 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000666 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000667 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000668 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000669 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000670
671 if (arraySize == 1 && count > 1)
672 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
673
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000674 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000675 GLboolean *boolParams = new GLboolean[count * 2];
676
677 for (int i = 0; i < count * 2; ++i)
678 {
679 if (v[i] == 0)
680 {
681 boolParams[i] = GL_FALSE;
682 }
683 else
684 {
685 boolParams[i] = GL_TRUE;
686 }
687 }
688
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000689 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
690 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000691
692 delete [] boolParams;
693 }
694 else
695 {
696 return false;
697 }
698
699 return true;
700}
701
702bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
703{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000704 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000705 {
706 return false;
707 }
708
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000709 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000710 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000711
712 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000713 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000714 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000715
716 if (arraySize == 1 && count > 1)
717 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
718
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000719 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000720
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000721 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
722 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000723 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000724 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000725 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000726 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000727
728 if (arraySize == 1 && count > 1)
729 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
730
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000731 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000732 GLboolean *boolParams = new GLboolean[count * 3];
733
734 for (int i = 0; i < count * 3; ++i)
735 {
736 if (v[i] == 0)
737 {
738 boolParams[i] = GL_FALSE;
739 }
740 else
741 {
742 boolParams[i] = GL_TRUE;
743 }
744 }
745
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000746 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
747 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000748
749 delete [] boolParams;
750 }
751 else
752 {
753 return false;
754 }
755
756 return true;
757}
758
759bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
760{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000761 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000762 {
763 return false;
764 }
765
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000766 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000767 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000768
769 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000770 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000771 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000772
773 if (arraySize == 1 && count > 1)
774 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
775
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000776 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000777
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000778 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
779 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000780 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000781 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000782 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000783 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000784
785 if (arraySize == 1 && count > 1)
786 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
787
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000788 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000789 GLboolean *boolParams = new GLboolean[count * 4];
790
791 for (int i = 0; i < count * 4; ++i)
792 {
793 if (v[i] == 0)
794 {
795 boolParams[i] = GL_FALSE;
796 }
797 else
798 {
799 boolParams[i] = GL_TRUE;
800 }
801 }
802
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000803 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
804 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000805
806 delete [] boolParams;
807 }
808 else
809 {
810 return false;
811 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000812
813 return true;
814}
815
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000816bool Program::getUniformfv(GLint location, GLfloat *params)
817{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000818 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000819 {
820 return false;
821 }
822
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000823 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000824
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000825 unsigned int count = UniformComponentCount(targetUniform->type);
826
827 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000828 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000829 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000830 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000831 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000832
833 for (unsigned int i = 0; i < count; ++i)
834 {
835 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
836 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000837 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000838 break;
839 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000840 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
841 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000842 break;
843 case GL_INT:
844 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000845 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000846
847 for (unsigned int i = 0; i < count; ++i)
848 {
849 params[i] = (float)intParams[i];
850 }
851 }
852 break;
853 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000854 }
855
856 return true;
857}
858
859bool Program::getUniformiv(GLint location, GLint *params)
860{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000861 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000862 {
863 return false;
864 }
865
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000866 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000867
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000868 unsigned int count = UniformComponentCount(targetUniform->type);
869
870 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000871 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000872 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000873 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000874 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000875
876 for (unsigned int i = 0; i < count; ++i)
877 {
878 params[i] = (GLint)boolParams[i];
879 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000880 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000881 break;
882 case GL_FLOAT:
883 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000884 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000885
886 for (unsigned int i = 0; i < count; ++i)
887 {
888 params[i] = (GLint)floatParams[i];
889 }
890 }
891 break;
892 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000893 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
894 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000895 break;
896 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000897 }
898
899 return true;
900}
901
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000902void Program::dirtyAllUniforms()
903{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000904 unsigned int numUniforms = mUniforms.size();
905 for (unsigned int index = 0; index < numUniforms; index++)
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000906 {
907 mUniforms[index]->dirty = true;
908 }
909}
910
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000911void Program::dirtyAllSamplers()
912{
913 for (unsigned int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; ++index)
914 {
915 mSamplers[index].dirty = true;
916 }
917}
918
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000919// Applies all the uniforms set for this program object to the Direct3D 9 device
920void Program::applyUniforms()
921{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000922 unsigned int numUniforms = mUniformIndex.size();
923 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000924 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000925 if (mUniformIndex[location].element != 0)
926 {
927 continue;
928 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000929
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000930 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
931
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000932 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000933 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000934 int arraySize = targetUniform->arraySize;
935 GLfloat *f = (GLfloat*)targetUniform->data;
936 GLint *i = (GLint*)targetUniform->data;
937 GLboolean *b = (GLboolean*)targetUniform->data;
938
939 switch (targetUniform->type)
940 {
941 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
942 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
943 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
944 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
945 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
946 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
947 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
948 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
949 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
950 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
951 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
952 case GL_INT: applyUniform1iv(location, arraySize, i); break;
953 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
954 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
955 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
956 default:
957 UNREACHABLE();
958 }
959
960 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000961 }
962 }
963}
964
965// Compiles the HLSL code of the attached shaders into executable binaries
966ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
967{
968 if (!hlsl)
969 {
970 return NULL;
971 }
972
973 ID3DXBuffer *binary = NULL;
974 ID3DXBuffer *errorMessage = NULL;
975
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000976 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, NULL, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000977
978 if (SUCCEEDED(result))
979 {
980 return binary;
981 }
982
983 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
984 {
985 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
986 }
987
988 if (errorMessage)
989 {
990 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000991
daniel@transgaming.com0df16872010-05-12 16:51:08 +0000992 appendToInfoLog("%s\n", message);
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000993 TRACE("\n%s", hlsl);
994 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000995 }
996
997 return NULL;
998}
999
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001000// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1001// Returns the number of used varying registers, or -1 if unsuccesful
1002int Program::packVaryings(const Varying *packing[][4])
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001003{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001004 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001005 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001006 int n = VariableRowCount(varying->type) * varying->size;
1007 int m = VariableColumnCount(varying->type);
1008 bool success = false;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001009
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001010 if (m == 2 || m == 3 || m == 4)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001011 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001012 for (int r = 0; r <= MAX_VARYING_VECTORS - n && !success; r++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001013 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001014 bool available = true;
1015
1016 for (int y = 0; y < n && available; y++)
1017 {
1018 for (int x = 0; x < m && available; x++)
1019 {
1020 if (packing[r + y][x])
1021 {
1022 available = false;
1023 }
1024 }
1025 }
1026
1027 if (available)
1028 {
1029 varying->reg = r;
1030 varying->col = 0;
1031
1032 for (int y = 0; y < n; y++)
1033 {
1034 for (int x = 0; x < m; x++)
1035 {
1036 packing[r + y][x] = &*varying;
1037 }
1038 }
1039
1040 success = true;
1041 }
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001042 }
1043
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001044 if (!success && m == 2)
1045 {
1046 for (int r = MAX_VARYING_VECTORS - n; r >= 0 && !success; r--)
1047 {
1048 bool available = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001049
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001050 for (int y = 0; y < n && available; y++)
1051 {
1052 for (int x = 2; x < 4 && available; x++)
1053 {
1054 if (packing[r + y][x])
1055 {
1056 available = false;
1057 }
1058 }
1059 }
1060
1061 if (available)
1062 {
1063 varying->reg = r;
1064 varying->col = 2;
1065
1066 for (int y = 0; y < n; y++)
1067 {
1068 for (int x = 2; x < 4; x++)
1069 {
1070 packing[r + y][x] = &*varying;
1071 }
1072 }
1073
1074 success = true;
1075 }
1076 }
1077 }
1078 }
1079 else if (m == 1)
1080 {
1081 int space[4] = {0};
1082
1083 for (int y = 0; y < MAX_VARYING_VECTORS; y++)
1084 {
1085 for (int x = 0; x < 4; x++)
1086 {
1087 space[x] += packing[y][x] ? 0 : 1;
1088 }
1089 }
1090
1091 int column = 0;
1092
1093 for (int x = 0; x < 4; x++)
1094 {
1095 if (space[x] > n && space[x] < space[column])
1096 {
1097 column = x;
1098 }
1099 }
1100
1101 if (space[column] > n)
1102 {
1103 for (int r = 0; r < MAX_VARYING_VECTORS; r++)
1104 {
1105 if (!packing[r][column])
1106 {
1107 varying->reg = r;
1108
1109 for (int y = r; y < r + n; y++)
1110 {
1111 packing[y][column] = &*varying;
1112 }
1113
1114 break;
1115 }
1116 }
1117
1118 varying->col = column;
1119
1120 success = true;
1121 }
1122 }
1123 else UNREACHABLE();
1124
1125 if (!success)
1126 {
1127 appendToInfoLog("Could not pack varying %s", varying->name.c_str());
1128
1129 return -1;
1130 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001131 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001132
1133 // Return the number of used registers
1134 int registers = 0;
1135
1136 for (int r = 0; r < MAX_VARYING_VECTORS; r++)
1137 {
1138 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1139 {
1140 registers++;
1141 }
1142 }
1143
1144 return registers;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001145}
1146
1147bool Program::linkVaryings()
1148{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001149 if (mPixelHLSL.empty() || mVertexHLSL.empty())
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001150 {
1151 return false;
1152 }
1153
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001154 const Varying *packing[MAX_VARYING_VECTORS][4] = {NULL};
1155 int registers = packVaryings(packing);
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001156
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001157 if (registers < 0)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001158 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001159 return false;
1160 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001161
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001162 if (registers == MAX_VARYING_VECTORS && mFragmentShader->mUsesFragCoord)
1163 {
1164 appendToInfoLog("No varying registers left to support gl_FragCoord");
1165
1166 return false;
1167 }
1168
1169 for (VaryingList::iterator input = mFragmentShader->varyings.begin(); input != mFragmentShader->varyings.end(); input++)
1170 {
1171 bool matched = false;
1172
1173 for (VaryingList::iterator output = mVertexShader->varyings.begin(); output != mVertexShader->varyings.end(); output++)
1174 {
1175 if (output->name == input->name)
1176 {
1177 if (output->type != input->type || output->size != input->size)
1178 {
1179 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
1180
1181 return false;
1182 }
1183
1184 output->reg = input->reg;
1185 output->col = input->col;
1186
1187 matched = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001188 break;
1189 }
1190 }
1191
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001192 if (!matched)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001193 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001194 appendToInfoLog("Fragment varying varying %s does not match any vertex varying", input->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001195
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001196 return false;
1197 }
1198 }
1199
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001200 Context *context = getContext();
1201 bool sm3 = context->supportsShaderModel3();
1202 std::string varyingSemantic = (sm3 ? "COLOR" : "TEXCOORD");
1203
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001204 mVertexHLSL += "struct VS_INPUT\n"
1205 "{\n";
1206
1207 int semanticIndex = 0;
1208 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1209 {
1210 switch (attribute->type)
1211 {
1212 case GL_FLOAT: mVertexHLSL += " float "; break;
1213 case GL_FLOAT_VEC2: mVertexHLSL += " float2 "; break;
1214 case GL_FLOAT_VEC3: mVertexHLSL += " float3 "; break;
1215 case GL_FLOAT_VEC4: mVertexHLSL += " float4 "; break;
1216 case GL_FLOAT_MAT2: mVertexHLSL += " float2x2 "; break;
1217 case GL_FLOAT_MAT3: mVertexHLSL += " float3x3 "; break;
1218 case GL_FLOAT_MAT4: mVertexHLSL += " float4x4 "; break;
1219 default: UNREACHABLE();
1220 }
1221
1222 mVertexHLSL += decorate(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1223
1224 semanticIndex += VariableRowCount(attribute->type);
1225 }
1226
1227 mVertexHLSL += "};\n"
1228 "\n"
1229 "struct VS_OUTPUT\n"
1230 "{\n"
1231 " float4 gl_Position : POSITION;\n";
1232
1233 for (int r = 0; r < registers; r++)
1234 {
1235 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1236
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001237 mVertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001238 }
1239
1240 if (mFragmentShader->mUsesFragCoord)
1241 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001242 mVertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1243 }
1244
1245 if (mVertexShader->mUsesPointSize && sm3)
1246 {
1247 mVertexHLSL += " float gl_PointSize : PSIZE;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001248 }
1249
1250 mVertexHLSL += "};\n"
1251 "\n"
1252 "VS_OUTPUT main(VS_INPUT input)\n"
1253 "{\n";
1254
1255 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1256 {
1257 mVertexHLSL += " " + decorate(attribute->name) + " = ";
1258
1259 if (VariableRowCount(attribute->type) > 1) // Matrix
1260 {
1261 mVertexHLSL += "transpose";
1262 }
1263
1264 mVertexHLSL += "(input." + decorate(attribute->name) + ");\n";
1265 }
1266
1267 mVertexHLSL += "\n"
1268 " gl_main();\n"
1269 "\n"
1270 " VS_OUTPUT output;\n"
1271 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
1272 " output.gl_Position.y = -(gl_Position.y - dx_HalfPixelSize.y * gl_Position.w);\n"
1273 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1274 " output.gl_Position.w = gl_Position.w;\n";
1275
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001276 if (mVertexShader->mUsesPointSize && sm3)
1277 {
1278 mVertexHLSL += " output.gl_PointSize = clamp(gl_PointSize, 1.0, " + str((int)ALIASED_POINT_SIZE_RANGE_MAX_SM3) + ");\n";
1279 }
1280
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001281 if (mFragmentShader->mUsesFragCoord)
1282 {
1283 mVertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1284 }
1285
1286 for (VaryingList::iterator varying = mVertexShader->varyings.begin(); varying != mVertexShader->varyings.end(); varying++)
1287 {
1288 if (varying->reg >= 0)
1289 {
1290 for (int i = 0; i < varying->size; i++)
1291 {
1292 int rows = VariableRowCount(varying->type);
1293
1294 for (int j = 0; j < rows; j++)
1295 {
1296 int r = varying->reg + i * rows + j;
1297 mVertexHLSL += " output.v" + str(r);
1298
1299 bool sharedRegister = false; // Register used by multiple varyings
1300
1301 for (int x = 0; x < 4; x++)
1302 {
1303 if (packing[r][x] && packing[r][x] != packing[r][0])
1304 {
1305 sharedRegister = true;
1306 break;
1307 }
1308 }
1309
1310 if(sharedRegister)
1311 {
1312 mVertexHLSL += ".";
1313
1314 for (int x = 0; x < 4; x++)
1315 {
1316 if (packing[r][x] == &*varying)
1317 {
1318 switch(x)
1319 {
1320 case 0: mVertexHLSL += "x"; break;
1321 case 1: mVertexHLSL += "y"; break;
1322 case 2: mVertexHLSL += "z"; break;
1323 case 3: mVertexHLSL += "w"; break;
1324 }
1325 }
1326 }
1327 }
1328
1329 mVertexHLSL += " = " + varying->name;
1330
1331 if (varying->array)
1332 {
1333 mVertexHLSL += "[" + str(i) + "]";
1334 }
1335
1336 if (rows > 1)
1337 {
1338 mVertexHLSL += "[" + str(j) + "]";
1339 }
1340
1341 mVertexHLSL += ";\n";
1342 }
1343 }
1344 }
1345 }
1346
1347 mVertexHLSL += "\n"
1348 " return output;\n"
1349 "}\n";
1350
1351 mPixelHLSL += "struct PS_INPUT\n"
1352 "{\n";
1353
1354 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1355 {
1356 if (varying->reg >= 0)
1357 {
1358 for (int i = 0; i < varying->size; i++)
1359 {
1360 int rows = VariableRowCount(varying->type);
1361 for (int j = 0; j < rows; j++)
1362 {
1363 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001364 mPixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001365 }
1366 }
1367 }
1368 else UNREACHABLE();
1369 }
1370
1371 if (mFragmentShader->mUsesFragCoord)
1372 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001373 mPixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001374 }
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001375
1376 if (mFragmentShader->mUsesPointCoord && sm3)
1377 {
1378 mPixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1379 }
1380
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001381 if (mFragmentShader->mUsesFrontFacing)
1382 {
1383 mPixelHLSL += " float vFace : VFACE;\n";
1384 }
1385
1386 mPixelHLSL += "};\n"
1387 "\n"
1388 "struct PS_OUTPUT\n"
1389 "{\n"
1390 " float4 gl_Color[1] : COLOR;\n"
1391 "};\n"
1392 "\n"
1393 "PS_OUTPUT main(PS_INPUT input)\n"
1394 "{\n";
1395
1396 if (mFragmentShader->mUsesFragCoord)
1397 {
1398 mPixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n"
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00001399 " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Viewport.x + dx_Viewport.z;\n"
1400 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Viewport.y + dx_Viewport.w;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001401 " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
1402 " gl_FragCoord.w = rhw;\n";
1403 }
1404
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001405 if (mFragmentShader->mUsesPointCoord && sm3)
1406 {
1407 mPixelHLSL += " gl_PointCoord = float2(input.gl_PointCoord.x, 1.0 - input.gl_PointCoord.y);\n";
1408 }
1409
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001410 if (mFragmentShader->mUsesFrontFacing)
1411 {
1412 mPixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1413 }
1414
1415 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1416 {
1417 if (varying->reg >= 0)
1418 {
1419 for (int i = 0; i < varying->size; i++)
1420 {
1421 int rows = VariableRowCount(varying->type);
1422 for (int j = 0; j < rows; j++)
1423 {
1424 std::string n = str(varying->reg + i * rows + j);
1425 mPixelHLSL += " " + varying->name;
1426
1427 if (varying->array)
1428 {
1429 mPixelHLSL += "[" + str(i) + "]";
1430 }
1431
1432 if (rows > 1)
1433 {
1434 mPixelHLSL += "[" + str(j) + "]";
1435 }
1436
1437 mPixelHLSL += " = input.v" + n + ";\n";
1438 }
1439 }
1440 }
1441 else UNREACHABLE();
1442 }
1443
1444 mPixelHLSL += "\n"
1445 " gl_main();\n"
1446 "\n"
1447 " PS_OUTPUT output;\n"
1448 " output.gl_Color[0] = gl_Color[0];\n"
1449 "\n"
1450 " return output;\n"
1451 "}\n";
1452
1453 TRACE("\n%s", mPixelHLSL.c_str());
1454 TRACE("\n%s", mVertexHLSL.c_str());
1455
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001456 return true;
1457}
1458
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001459// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1460// compiling them into binaries, determining the attribute mappings, and collecting
1461// a list of uniforms
1462void Program::link()
1463{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001464 unlink();
1465
1466 if (!mFragmentShader || !mFragmentShader->isCompiled())
1467 {
1468 return;
1469 }
1470
1471 if (!mVertexShader || !mVertexShader->isCompiled())
1472 {
1473 return;
1474 }
1475
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001476 mPixelHLSL = mFragmentShader->getHLSL();
1477 mVertexHLSL = mVertexShader->getHLSL();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001478
1479 if (!linkVaryings())
1480 {
1481 return;
1482 }
1483
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001484 Context *context = getContext();
1485 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1486 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1487
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001488 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1489 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001490
1491 if (vertexBinary && pixelBinary)
1492 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001493 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001494 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1495 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1496
1497 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1498 {
1499 return error(GL_OUT_OF_MEMORY);
1500 }
1501
1502 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001503
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001504 vertexBinary->Release();
1505 pixelBinary->Release();
1506 vertexBinary = NULL;
1507 pixelBinary = NULL;
1508
1509 if (mVertexExecutable && mPixelExecutable)
1510 {
1511 if (!linkAttributes())
1512 {
1513 return;
1514 }
1515
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001516 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001517 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001518 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001519 }
1520
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001521 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001522 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001523 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001524 }
1525
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001526 // these uniforms are searched as already-decorated because gl_ and dx_
1527 // are reserved prefixes, and do not receive additional decoration
1528 mDepthRangeNearLocation = getUniformLocation("gl_DepthRange.near", true);
1529 mDepthRangeFarLocation = getUniformLocation("gl_DepthRange.far", true);
1530 mDepthRangeDiffLocation = getUniformLocation("gl_DepthRange.diff", true);
1531 mDxDepthLocation = getUniformLocation("dx_Depth", true);
daniel@transgaming.com162267d2010-07-28 19:20:48 +00001532 mDxViewportLocation = getUniformLocation("dx_Viewport", true);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001533 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize", true);
1534 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW", true);
1535 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines", true);
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00001536
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001537 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001538 }
1539 }
1540}
1541
1542// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1543bool Program::linkAttributes()
1544{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001545 unsigned int usedLocations = 0;
1546
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001547 // Link attributes that have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001548 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001549 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001550 int location = getAttributeBinding(attribute->name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001551
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001552 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001553 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001554 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001555 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001556 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001557 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001558
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001559 mLinkedAttribute[location] = *attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001560
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001561 int rows = VariableRowCount(attribute->type);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001562
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001563 if (rows + location > MAX_VERTEX_ATTRIBS)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001564 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001565 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 +00001566
1567 return false;
1568 }
1569
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001570 for (int i = 0; i < rows; i++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001571 {
1572 usedLocations |= 1 << (location + i);
1573 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001574 }
1575 }
1576
1577 // Link attributes that don't have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001578 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001579 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001580 int location = getAttributeBinding(attribute->name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001581
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001582 if (location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001583 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001584 int rows = VariableRowCount(attribute->type);
1585 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001586
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001587 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001588 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001589 appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001590
1591 return false; // Fail to link
1592 }
1593
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001594 mLinkedAttribute[availableIndex] = *attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001595 }
1596 }
1597
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001598 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001599 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001600 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001601 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001602
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001603 for (int r = 0; r < rows; r++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001604 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001605 mSemanticIndex[attributeIndex++] = index++;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001606 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001607 }
1608
1609 return true;
1610}
1611
daniel@transgaming.com85423182010-04-22 13:35:27 +00001612int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001613{
1614 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1615 {
1616 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1617 {
1618 return location;
1619 }
1620 }
1621
1622 return -1;
1623}
1624
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001625bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1626{
1627 D3DXCONSTANTTABLE_DESC constantTableDescription;
1628 D3DXCONSTANT_DESC constantDescription;
1629 UINT descriptionCount = 1;
1630
1631 constantTable->GetDesc(&constantTableDescription);
1632
1633 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1634 {
1635 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1636 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1637
1638 if (!defineUniform(constantHandle, constantDescription))
1639 {
1640 return false;
1641 }
1642 }
1643
1644 return true;
1645}
1646
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001647// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001648// Returns true if succesful (uniform not already defined)
1649bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1650{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001651 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1652 {
1653 unsigned int samplerIndex = constantDescription.RegisterIndex;
1654
1655 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1656
1657 mSamplers[samplerIndex].active = true;
1658 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1659 mSamplers[samplerIndex].logicalTextureUnit = 0;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001660 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001661 }
1662
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001663 switch(constantDescription.Class)
1664 {
1665 case D3DXPC_STRUCT:
1666 {
1667 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1668 {
1669 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1670
1671 D3DXCONSTANT_DESC fieldDescription;
1672 UINT descriptionCount = 1;
1673
1674 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1675
1676 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1677 {
1678 return false;
1679 }
1680 }
1681
1682 return true;
1683 }
1684 case D3DXPC_SCALAR:
1685 case D3DXPC_VECTOR:
1686 case D3DXPC_MATRIX_COLUMNS:
1687 case D3DXPC_OBJECT:
1688 return defineUniform(constantDescription, name + constantDescription.Name);
1689 default:
1690 UNREACHABLE();
1691 return false;
1692 }
1693}
1694
1695bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1696{
1697 Uniform *uniform = createUniform(constantDescription, name);
1698
1699 if(!uniform)
1700 {
1701 return false;
1702 }
1703
1704 // Check if already defined
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001705 GLint location = getUniformLocation(name.c_str(), true);
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001706 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001707
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001708 if (location >= 0)
1709 {
1710 delete uniform;
1711
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001712 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001713 {
1714 return false;
1715 }
1716 else
1717 {
1718 return true;
1719 }
1720 }
1721
1722 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001723 unsigned int uniformIndex = mUniforms.size() - 1;
1724
1725 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1726 {
1727 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1728 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001729
1730 return true;
1731}
1732
1733Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001734{
1735 if (constantDescription.Rows == 1) // Vectors and scalars
1736 {
1737 switch (constantDescription.Type)
1738 {
1739 case D3DXPT_SAMPLER2D:
1740 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001741 switch (constantDescription.Columns)
1742 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001743 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001744 default: UNREACHABLE();
1745 }
1746 break;
1747 case D3DXPT_BOOL:
1748 switch (constantDescription.Columns)
1749 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001750 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1751 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1752 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1753 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001754 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001755 }
1756 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001757 case D3DXPT_INT:
1758 switch (constantDescription.Columns)
1759 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001760 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1761 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1762 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1763 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001764 default: UNREACHABLE();
1765 }
1766 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001767 case D3DXPT_FLOAT:
1768 switch (constantDescription.Columns)
1769 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001770 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1771 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1772 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1773 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001774 default: UNREACHABLE();
1775 }
1776 break;
1777 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001778 UNREACHABLE();
1779 }
1780 }
1781 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1782 {
1783 switch (constantDescription.Type)
1784 {
1785 case D3DXPT_FLOAT:
1786 switch (constantDescription.Rows)
1787 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001788 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1789 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1790 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001791 default: UNREACHABLE();
1792 }
1793 break;
1794 default: UNREACHABLE();
1795 }
1796 }
1797 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001798
1799 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001800}
1801
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001802// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001803std::string Program::decorate(const std::string &string)
1804{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001805 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001806 {
1807 return "_" + string;
1808 }
1809 else
1810 {
1811 return string;
1812 }
1813}
1814
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001815std::string Program::undecorate(const std::string &string)
1816{
1817 if (string.substr(0, 1) == "_")
1818 {
1819 return string.substr(1);
1820 }
1821 else
1822 {
1823 return string;
1824 }
1825}
1826
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001827bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1828{
1829 BOOL *vector = new BOOL[count];
1830 for (int i = 0; i < count; i++)
1831 {
1832 if (v[i] == GL_FALSE)
1833 vector[i] = 0;
1834 else
1835 vector[i] = 1;
1836 }
1837
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001838 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1839
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001840 D3DXHANDLE constantPS;
1841 D3DXHANDLE constantVS;
1842 getConstantHandles(targetUniform, &constantPS, &constantVS);
1843
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001844 IDirect3DDevice9 *device = getDevice();
1845
1846 if (constantPS)
1847 {
1848 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1849 }
1850
1851 if (constantVS)
1852 {
1853 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1854 }
1855
1856 delete [] vector;
1857
1858 return true;
1859}
1860
1861bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1862{
1863 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1864
1865 for (int i = 0; i < count; i++)
1866 {
1867 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1868 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1869
1870 v += 2;
1871 }
1872
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001873 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1874
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001875 D3DXHANDLE constantPS;
1876 D3DXHANDLE constantVS;
1877 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001878 IDirect3DDevice9 *device = getDevice();
1879
1880 if (constantPS)
1881 {
1882 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1883 }
1884
1885 if (constantVS)
1886 {
1887 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1888 }
1889
1890 delete[] vector;
1891
1892 return true;
1893}
1894
1895bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1896{
1897 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1898
1899 for (int i = 0; i < count; i++)
1900 {
1901 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1902 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1903 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1904
1905 v += 3;
1906 }
1907
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001908 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1909
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001910 D3DXHANDLE constantPS;
1911 D3DXHANDLE constantVS;
1912 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001913 IDirect3DDevice9 *device = getDevice();
1914
1915 if (constantPS)
1916 {
1917 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1918 }
1919
1920 if (constantVS)
1921 {
1922 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1923 }
1924
1925 delete[] vector;
1926
1927 return true;
1928}
1929
1930bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1931{
1932 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1933
1934 for (int i = 0; i < count; i++)
1935 {
1936 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1937 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1938 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1939 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1940
1941 v += 3;
1942 }
1943
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001944 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1945
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001946 D3DXHANDLE constantPS;
1947 D3DXHANDLE constantVS;
1948 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001949 IDirect3DDevice9 *device = getDevice();
1950
1951 if (constantPS)
1952 {
1953 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1954 }
1955
1956 if (constantVS)
1957 {
1958 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1959 }
1960
1961 delete [] vector;
1962
1963 return true;
1964}
1965
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001966bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1967{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001968 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1969
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001970 D3DXHANDLE constantPS;
1971 D3DXHANDLE constantVS;
1972 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001973 IDirect3DDevice9 *device = getDevice();
1974
1975 if (constantPS)
1976 {
1977 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1978 }
1979
1980 if (constantVS)
1981 {
1982 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1983 }
1984
1985 return true;
1986}
1987
1988bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1989{
1990 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1991
1992 for (int i = 0; i < count; i++)
1993 {
1994 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1995
1996 v += 2;
1997 }
1998
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001999 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2000
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002001 D3DXHANDLE constantPS;
2002 D3DXHANDLE constantVS;
2003 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002004 IDirect3DDevice9 *device = getDevice();
2005
2006 if (constantPS)
2007 {
2008 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2009 }
2010
2011 if (constantVS)
2012 {
2013 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2014 }
2015
2016 delete[] vector;
2017
2018 return true;
2019}
2020
2021bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
2022{
2023 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2024
2025 for (int i = 0; i < count; i++)
2026 {
2027 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
2028
2029 v += 3;
2030 }
2031
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002032 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2033
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002034 D3DXHANDLE constantPS;
2035 D3DXHANDLE constantVS;
2036 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002037 IDirect3DDevice9 *device = getDevice();
2038
2039 if (constantPS)
2040 {
2041 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2042 }
2043
2044 if (constantVS)
2045 {
2046 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2047 }
2048
2049 delete[] vector;
2050
2051 return true;
2052}
2053
2054bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
2055{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002056 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2057
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002058 D3DXHANDLE constantPS;
2059 D3DXHANDLE constantVS;
2060 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002061 IDirect3DDevice9 *device = getDevice();
2062
2063 if (constantPS)
2064 {
2065 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
2066 }
2067
2068 if (constantVS)
2069 {
2070 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
2071 }
2072
2073 return true;
2074}
2075
2076bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
2077{
2078 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2079
2080 for (int i = 0; i < count; i++)
2081 {
2082 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
2083 value[1], value[3], 0, 0,
2084 0, 0, 1, 0,
2085 0, 0, 0, 1);
2086
2087 value += 4;
2088 }
2089
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002090 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2091
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002092 D3DXHANDLE constantPS;
2093 D3DXHANDLE constantVS;
2094 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002095 IDirect3DDevice9 *device = getDevice();
2096
2097 if (constantPS)
2098 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002099 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002100 }
2101
2102 if (constantVS)
2103 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002104 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002105 }
2106
2107 delete[] matrix;
2108
2109 return true;
2110}
2111
2112bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
2113{
2114 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2115
2116 for (int i = 0; i < count; i++)
2117 {
2118 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
2119 value[1], value[4], value[7], 0,
2120 value[2], value[5], value[8], 0,
2121 0, 0, 0, 1);
2122
2123 value += 9;
2124 }
2125
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002126 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2127
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002128 D3DXHANDLE constantPS;
2129 D3DXHANDLE constantVS;
2130 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002131 IDirect3DDevice9 *device = getDevice();
2132
2133 if (constantPS)
2134 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002135 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002136 }
2137
2138 if (constantVS)
2139 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002140 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002141 }
2142
2143 delete[] matrix;
2144
2145 return true;
2146}
2147
2148bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
2149{
2150 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2151
2152 for (int i = 0; i < count; i++)
2153 {
2154 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
2155 value[1], value[5], value[9], value[13],
2156 value[2], value[6], value[10], value[14],
2157 value[3], value[7], value[11], value[15]);
2158
2159 value += 16;
2160 }
2161
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002162 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2163
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002164 D3DXHANDLE constantPS;
2165 D3DXHANDLE constantVS;
2166 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002167 IDirect3DDevice9 *device = getDevice();
2168
2169 if (constantPS)
2170 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002171 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002172 }
2173
2174 if (constantVS)
2175 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002176 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002177 }
2178
2179 delete[] matrix;
2180
2181 return true;
2182}
2183
2184bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
2185{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002186 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2187
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002188 D3DXHANDLE constantPS;
2189 D3DXHANDLE constantVS;
2190 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002191 IDirect3DDevice9 *device = getDevice();
2192
2193 if (constantPS)
2194 {
2195 D3DXCONSTANT_DESC constantDescription;
2196 UINT descriptionCount = 1;
2197 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
2198
daniel@transgaming.com2884b782010-03-08 21:30:48 +00002199 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002200 {
2201 return false;
2202 }
2203
2204 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2205 {
2206 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
2207
2208 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
2209 {
2210 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002211
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002212 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002213 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002214 ASSERT(mSamplers[samplerIndex].active);
2215 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
2216 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002217 }
2218 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002219
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002220 return true;
2221 }
2222 }
2223
2224 if (constantPS)
2225 {
2226 mConstantTablePS->SetIntArray(device, constantPS, v, count);
2227 }
2228
2229 if (constantVS)
2230 {
2231 mConstantTableVS->SetIntArray(device, constantVS, v, count);
2232 }
2233
2234 return true;
2235}
2236
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002237bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
2238{
2239 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2240
2241 for (int i = 0; i < count; i++)
2242 {
2243 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2244
2245 v += 2;
2246 }
2247
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002248 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2249
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002250 D3DXHANDLE constantPS;
2251 D3DXHANDLE constantVS;
2252 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002253 IDirect3DDevice9 *device = getDevice();
2254
2255 if (constantPS)
2256 {
2257 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2258 }
2259
2260 if (constantVS)
2261 {
2262 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2263 }
2264
2265 delete[] vector;
2266
2267 return true;
2268}
2269
2270bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
2271{
2272 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2273
2274 for (int i = 0; i < count; i++)
2275 {
2276 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2277
2278 v += 3;
2279 }
2280
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002281 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2282
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002283 D3DXHANDLE constantPS;
2284 D3DXHANDLE constantVS;
2285 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002286 IDirect3DDevice9 *device = getDevice();
2287
2288 if (constantPS)
2289 {
2290 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2291 }
2292
2293 if (constantVS)
2294 {
2295 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2296 }
2297
2298 delete[] vector;
2299
2300 return true;
2301}
2302
2303bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
2304{
2305 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2306
2307 for (int i = 0; i < count; i++)
2308 {
2309 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2310
2311 v += 4;
2312 }
2313
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002314 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2315
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002316 D3DXHANDLE constantPS;
2317 D3DXHANDLE constantVS;
2318 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002319 IDirect3DDevice9 *device = getDevice();
2320
2321 if (constantPS)
2322 {
2323 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2324 }
2325
2326 if (constantVS)
2327 {
2328 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2329 }
2330
2331 delete [] vector;
2332
2333 return true;
2334}
2335
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002336void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002337{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002338 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002339 {
2340 return;
2341 }
2342
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002343 char info[1024];
2344
2345 va_list vararg;
2346 va_start(vararg, format);
2347 vsnprintf(info, sizeof(info), format, vararg);
2348 va_end(vararg);
2349
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002350 size_t infoLength = strlen(info);
2351
2352 if (!mInfoLog)
2353 {
2354 mInfoLog = new char[infoLength + 1];
2355 strcpy(mInfoLog, info);
2356 }
2357 else
2358 {
2359 size_t logLength = strlen(mInfoLog);
2360 char *newLog = new char[logLength + infoLength + 1];
2361 strcpy(newLog, mInfoLog);
2362 strcpy(newLog + logLength, info);
2363
2364 delete[] mInfoLog;
2365 mInfoLog = newLog;
2366 }
2367}
2368
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002369void Program::resetInfoLog()
2370{
2371 if (mInfoLog)
2372 {
2373 delete [] mInfoLog;
2374 }
2375}
2376
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002377// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
2378void Program::unlink(bool destroy)
2379{
2380 if (destroy) // Object being destructed
2381 {
2382 if (mFragmentShader)
2383 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002384 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002385 mFragmentShader = NULL;
2386 }
2387
2388 if (mVertexShader)
2389 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002390 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002391 mVertexShader = NULL;
2392 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002393 }
2394
2395 if (mPixelExecutable)
2396 {
2397 mPixelExecutable->Release();
2398 mPixelExecutable = NULL;
2399 }
2400
2401 if (mVertexExecutable)
2402 {
2403 mVertexExecutable->Release();
2404 mVertexExecutable = NULL;
2405 }
2406
2407 if (mConstantTablePS)
2408 {
2409 mConstantTablePS->Release();
2410 mConstantTablePS = NULL;
2411 }
2412
2413 if (mConstantTableVS)
2414 {
2415 mConstantTableVS->Release();
2416 mConstantTableVS = NULL;
2417 }
2418
2419 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2420 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002421 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002422 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002423 }
2424
2425 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2426 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00002427 mSamplers[index].active = false;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00002428 mSamplers[index].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002429 }
2430
2431 while (!mUniforms.empty())
2432 {
2433 delete mUniforms.back();
2434 mUniforms.pop_back();
2435 }
2436
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002437 mDepthRangeDiffLocation = -1;
2438 mDepthRangeNearLocation = -1;
2439 mDepthRangeFarLocation = -1;
2440 mDxDepthLocation = -1;
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002441 mDxViewportLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002442 mDxHalfPixelSizeLocation = -1;
2443 mDxFrontCCWLocation = -1;
2444 mDxPointsOrLinesLocation = -1;
2445
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002446 mUniformIndex.clear();
2447
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002448 mPixelHLSL.clear();
2449 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002450
2451 delete[] mInfoLog;
2452 mInfoLog = NULL;
2453
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002454 mLinked = false;
2455}
2456
2457bool Program::isLinked()
2458{
2459 return mLinked;
2460}
2461
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002462bool Program::isValidated() const
2463{
2464 return mValidated;
2465}
2466
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002467void Program::release()
2468{
2469 mRefCount--;
2470
2471 if (mRefCount == 0 && mDeleteStatus)
2472 {
2473 mResourceManager->deleteProgram(mHandle);
2474 }
2475}
2476
2477void Program::addRef()
2478{
2479 mRefCount++;
2480}
2481
2482unsigned int Program::getRefCount() const
2483{
2484 return mRefCount;
2485}
2486
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002487unsigned int Program::getSerial() const
2488{
2489 return mSerial;
2490}
2491
2492unsigned int Program::issueSerial()
2493{
2494 return mCurrentSerial++;
2495}
2496
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002497int Program::getInfoLogLength() const
2498{
2499 if (!mInfoLog)
2500 {
2501 return 0;
2502 }
2503 else
2504 {
2505 return strlen(mInfoLog) + 1;
2506 }
2507}
2508
2509void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2510{
2511 int index = 0;
2512
2513 if (mInfoLog)
2514 {
2515 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2516 {
2517 infoLog[index] = mInfoLog[index];
2518 index++;
2519 }
2520 }
2521
2522 if (bufSize)
2523 {
2524 infoLog[index] = '\0';
2525 }
2526
2527 if (length)
2528 {
2529 *length = index;
2530 }
2531}
2532
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002533void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2534{
2535 int total = 0;
2536
2537 if (mVertexShader)
2538 {
2539 if (total < maxCount)
2540 {
2541 shaders[total] = mVertexShader->getHandle();
2542 }
2543
2544 total++;
2545 }
2546
2547 if (mFragmentShader)
2548 {
2549 if (total < maxCount)
2550 {
2551 shaders[total] = mFragmentShader->getHandle();
2552 }
2553
2554 total++;
2555 }
2556
2557 if (count)
2558 {
2559 *count = total;
2560 }
2561}
2562
daniel@transgaming.com85423182010-04-22 13:35:27 +00002563void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2564{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002565 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002566 for (unsigned int i = 0; i < index; i++)
2567 {
2568 do
2569 {
2570 attribute++;
2571
2572 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2573 }
2574 while (mLinkedAttribute[attribute].name.empty());
2575 }
2576
2577 if (bufsize > 0)
2578 {
2579 const char *string = mLinkedAttribute[attribute].name.c_str();
2580
2581 strncpy(name, string, bufsize);
2582 name[bufsize - 1] = '\0';
2583
2584 if (length)
2585 {
2586 *length = strlen(name);
2587 }
2588 }
2589
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002590 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002591
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002592 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002593}
2594
2595GLint Program::getActiveAttributeCount()
2596{
2597 int count = 0;
2598
2599 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2600 {
2601 if (!mLinkedAttribute[attributeIndex].name.empty())
2602 {
2603 count++;
2604 }
2605 }
2606
2607 return count;
2608}
2609
2610GLint Program::getActiveAttributeMaxLength()
2611{
2612 int maxLength = 0;
2613
2614 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2615 {
2616 if (!mLinkedAttribute[attributeIndex].name.empty())
2617 {
2618 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2619 }
2620 }
2621
2622 return maxLength;
2623}
2624
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002625void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2626{
2627 unsigned int uniform = 0;
2628 for (unsigned int i = 0; i < index; i++)
2629 {
2630 do
2631 {
2632 uniform++;
2633
2634 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2635 }
2636 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2637 }
2638
2639 if (bufsize > 0)
2640 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002641 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002642
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002643 if (mUniforms[uniform]->arraySize != 1)
2644 {
2645 string += "[0]";
2646 }
2647
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002648 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002649 name[bufsize - 1] = '\0';
2650
2651 if (length)
2652 {
2653 *length = strlen(name);
2654 }
2655 }
2656
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002657 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002658
2659 *type = mUniforms[uniform]->type;
2660}
2661
2662GLint Program::getActiveUniformCount()
2663{
2664 int count = 0;
2665
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002666 unsigned int numUniforms = mUniforms.size();
2667 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002668 {
2669 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2670 {
2671 count++;
2672 }
2673 }
2674
2675 return count;
2676}
2677
2678GLint Program::getActiveUniformMaxLength()
2679{
2680 int maxLength = 0;
2681
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002682 unsigned int numUniforms = mUniforms.size();
2683 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002684 {
2685 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2686 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002687 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002688 }
2689 }
2690
2691 return maxLength;
2692}
2693
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002694void Program::flagForDeletion()
2695{
2696 mDeleteStatus = true;
2697}
2698
2699bool Program::isFlaggedForDeletion() const
2700{
2701 return mDeleteStatus;
2702}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002703
2704void Program::validate()
2705{
2706 resetInfoLog();
2707
2708 if (!isLinked())
2709 {
2710 appendToInfoLog("Program has not been successfully linked.");
2711 mValidated = false;
2712 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002713 else
2714 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002715 applyUniforms();
2716 if (!validateSamplers())
2717 {
2718 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2719 mValidated = false;
2720 }
2721 else
2722 {
2723 mValidated = true;
2724 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002725 }
2726}
2727
2728bool Program::validateSamplers() const
2729{
2730 // if any two active samplers in a program are of different types, but refer to the same
2731 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2732 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2733 std::map<int, SamplerType> samplerMap;
2734 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2735 {
2736 if (mSamplers[i].active)
2737 {
2738 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2739 {
2740 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2741 return false;
2742 }
2743 else
2744 {
2745 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2746 }
2747 }
2748 }
2749
2750 return true;
2751}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002752
2753void Program::getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS)
2754{
2755 if (!targetUniform->handlesSet)
2756 {
2757 targetUniform->psHandle = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2758 targetUniform->vsHandle = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
2759 targetUniform->handlesSet = true;
2760 }
2761
2762 *constantPS = targetUniform->psHandle;
2763 *constantVS = targetUniform->vsHandle;
2764}
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002765
2766GLint Program::getDepthRangeDiffLocation() const
2767{
2768 return mDepthRangeDiffLocation;
2769}
2770
2771GLint Program::getDepthRangeNearLocation() const
2772{
daniel@transgaming.come0d7d432010-05-18 18:51:52 +00002773 return mDepthRangeNearLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002774}
2775
2776GLint Program::getDepthRangeFarLocation() const
2777{
2778 return mDepthRangeFarLocation;
2779}
2780
2781GLint Program::getDxDepthLocation() const
2782{
2783 return mDxDepthLocation;
2784}
2785
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002786GLint Program::getDxViewportLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002787{
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002788 return mDxViewportLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002789}
2790
2791GLint Program::getDxHalfPixelSizeLocation() const
2792{
2793 return mDxHalfPixelSizeLocation;
2794}
2795
2796GLint Program::getDxFrontCCWLocation() const
2797{
2798 return mDxFrontCCWLocation;
2799}
2800
2801GLint Program::getDxPointsOrLinesLocation() const
2802{
2803 return mDxPointsOrLinesLocation;
2804}
2805
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002806}