blob: ef966036e26d8e98b9b53403ae6d5ff9980cd190 [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
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000598 if (targetUniform->type == GL_INT ||
599 targetUniform->type == GL_SAMPLER_2D ||
600 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000601 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000602 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000603
604 if (arraySize == 1 && count > 1)
605 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
606
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000607 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000608
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000609 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
610 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000611 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000612 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000613 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000614 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000615
616 if (arraySize == 1 && count > 1)
617 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
618
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000619 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000620 GLboolean *boolParams = new GLboolean[count];
621
622 for (int i = 0; i < count; ++i)
623 {
624 if (v[i] == 0)
625 {
626 boolParams[i] = GL_FALSE;
627 }
628 else
629 {
630 boolParams[i] = GL_TRUE;
631 }
632 }
633
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000634 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
635 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000636
637 delete [] boolParams;
638 }
639 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000640 {
641 return false;
642 }
643
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000644 return true;
645}
646
647bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
648{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000649 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000650 {
651 return false;
652 }
653
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000654 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000655 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000656
657 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000658 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000659 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000660
661 if (arraySize == 1 && count > 1)
662 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
663
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000664 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000665
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000666 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
667 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000668 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000669 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000670 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000671 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000672
673 if (arraySize == 1 && count > 1)
674 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
675
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000676 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000677 GLboolean *boolParams = new GLboolean[count * 2];
678
679 for (int i = 0; i < count * 2; ++i)
680 {
681 if (v[i] == 0)
682 {
683 boolParams[i] = GL_FALSE;
684 }
685 else
686 {
687 boolParams[i] = GL_TRUE;
688 }
689 }
690
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000691 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
692 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000693
694 delete [] boolParams;
695 }
696 else
697 {
698 return false;
699 }
700
701 return true;
702}
703
704bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
705{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000706 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000707 {
708 return false;
709 }
710
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000711 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000712 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000713
714 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000715 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000716 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000717
718 if (arraySize == 1 && count > 1)
719 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
720
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000721 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000722
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000723 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
724 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000725 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000726 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000727 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000728 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000729
730 if (arraySize == 1 && count > 1)
731 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
732
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000733 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000734 GLboolean *boolParams = new GLboolean[count * 3];
735
736 for (int i = 0; i < count * 3; ++i)
737 {
738 if (v[i] == 0)
739 {
740 boolParams[i] = GL_FALSE;
741 }
742 else
743 {
744 boolParams[i] = GL_TRUE;
745 }
746 }
747
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000748 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
749 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000750
751 delete [] boolParams;
752 }
753 else
754 {
755 return false;
756 }
757
758 return true;
759}
760
761bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
762{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000763 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000764 {
765 return false;
766 }
767
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000768 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000769 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000770
771 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000772 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000773 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000774
775 if (arraySize == 1 && count > 1)
776 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
777
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000778 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000779
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000780 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
781 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000782 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000783 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000784 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000785 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000786
787 if (arraySize == 1 && count > 1)
788 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
789
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000790 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000791 GLboolean *boolParams = new GLboolean[count * 4];
792
793 for (int i = 0; i < count * 4; ++i)
794 {
795 if (v[i] == 0)
796 {
797 boolParams[i] = GL_FALSE;
798 }
799 else
800 {
801 boolParams[i] = GL_TRUE;
802 }
803 }
804
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000805 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
806 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000807
808 delete [] boolParams;
809 }
810 else
811 {
812 return false;
813 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000814
815 return true;
816}
817
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000818bool Program::getUniformfv(GLint location, GLfloat *params)
819{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000820 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000821 {
822 return false;
823 }
824
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000825 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000826
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000827 unsigned int count = UniformComponentCount(targetUniform->type);
828
829 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000830 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000831 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000832 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000833 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000834
835 for (unsigned int i = 0; i < count; ++i)
836 {
837 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
838 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000839 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000840 break;
841 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000842 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
843 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000844 break;
845 case GL_INT:
846 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000847 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000848
849 for (unsigned int i = 0; i < count; ++i)
850 {
851 params[i] = (float)intParams[i];
852 }
853 }
854 break;
855 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000856 }
857
858 return true;
859}
860
861bool Program::getUniformiv(GLint location, GLint *params)
862{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000863 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000864 {
865 return false;
866 }
867
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000868 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000869
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000870 unsigned int count = UniformComponentCount(targetUniform->type);
871
872 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000873 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000874 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000875 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000876 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000877
878 for (unsigned int i = 0; i < count; ++i)
879 {
880 params[i] = (GLint)boolParams[i];
881 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000882 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000883 break;
884 case GL_FLOAT:
885 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000886 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000887
888 for (unsigned int i = 0; i < count; ++i)
889 {
890 params[i] = (GLint)floatParams[i];
891 }
892 }
893 break;
894 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000895 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
896 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000897 break;
898 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000899 }
900
901 return true;
902}
903
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000904void Program::dirtyAllUniforms()
905{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000906 unsigned int numUniforms = mUniforms.size();
907 for (unsigned int index = 0; index < numUniforms; index++)
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000908 {
909 mUniforms[index]->dirty = true;
910 }
911}
912
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000913void Program::dirtyAllSamplers()
914{
915 for (unsigned int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; ++index)
916 {
917 mSamplers[index].dirty = true;
918 }
919}
920
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000921// Applies all the uniforms set for this program object to the Direct3D 9 device
922void Program::applyUniforms()
923{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000924 unsigned int numUniforms = mUniformIndex.size();
925 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000926 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000927 if (mUniformIndex[location].element != 0)
928 {
929 continue;
930 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000931
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000932 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
933
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000934 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000935 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000936 int arraySize = targetUniform->arraySize;
937 GLfloat *f = (GLfloat*)targetUniform->data;
938 GLint *i = (GLint*)targetUniform->data;
939 GLboolean *b = (GLboolean*)targetUniform->data;
940
941 switch (targetUniform->type)
942 {
943 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
944 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
945 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
946 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
947 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
948 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
949 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
950 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
951 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
952 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
953 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000954 case GL_SAMPLER_2D:
955 case GL_SAMPLER_CUBE:
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000956 case GL_INT: applyUniform1iv(location, arraySize, i); break;
957 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
958 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
959 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
960 default:
961 UNREACHABLE();
962 }
963
964 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000965 }
966 }
967}
968
969// Compiles the HLSL code of the attached shaders into executable binaries
970ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
971{
972 if (!hlsl)
973 {
974 return NULL;
975 }
976
977 ID3DXBuffer *binary = NULL;
978 ID3DXBuffer *errorMessage = NULL;
979
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000980 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, NULL, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000981
982 if (SUCCEEDED(result))
983 {
984 return binary;
985 }
986
987 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
988 {
989 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
990 }
991
992 if (errorMessage)
993 {
994 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000995
daniel@transgaming.com0df16872010-05-12 16:51:08 +0000996 appendToInfoLog("%s\n", message);
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000997 TRACE("\n%s", hlsl);
998 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000999 }
1000
1001 return NULL;
1002}
1003
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001004// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1005// Returns the number of used varying registers, or -1 if unsuccesful
1006int Program::packVaryings(const Varying *packing[][4])
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001007{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001008 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001009 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001010 int n = VariableRowCount(varying->type) * varying->size;
1011 int m = VariableColumnCount(varying->type);
1012 bool success = false;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001013
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001014 if (m == 2 || m == 3 || m == 4)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001015 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001016 for (int r = 0; r <= MAX_VARYING_VECTORS - n && !success; r++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001017 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001018 bool available = true;
1019
1020 for (int y = 0; y < n && available; y++)
1021 {
1022 for (int x = 0; x < m && available; x++)
1023 {
1024 if (packing[r + y][x])
1025 {
1026 available = false;
1027 }
1028 }
1029 }
1030
1031 if (available)
1032 {
1033 varying->reg = r;
1034 varying->col = 0;
1035
1036 for (int y = 0; y < n; y++)
1037 {
1038 for (int x = 0; x < m; x++)
1039 {
1040 packing[r + y][x] = &*varying;
1041 }
1042 }
1043
1044 success = true;
1045 }
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001046 }
1047
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001048 if (!success && m == 2)
1049 {
1050 for (int r = MAX_VARYING_VECTORS - n; r >= 0 && !success; r--)
1051 {
1052 bool available = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001053
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001054 for (int y = 0; y < n && available; y++)
1055 {
1056 for (int x = 2; x < 4 && available; x++)
1057 {
1058 if (packing[r + y][x])
1059 {
1060 available = false;
1061 }
1062 }
1063 }
1064
1065 if (available)
1066 {
1067 varying->reg = r;
1068 varying->col = 2;
1069
1070 for (int y = 0; y < n; y++)
1071 {
1072 for (int x = 2; x < 4; x++)
1073 {
1074 packing[r + y][x] = &*varying;
1075 }
1076 }
1077
1078 success = true;
1079 }
1080 }
1081 }
1082 }
1083 else if (m == 1)
1084 {
1085 int space[4] = {0};
1086
1087 for (int y = 0; y < MAX_VARYING_VECTORS; y++)
1088 {
1089 for (int x = 0; x < 4; x++)
1090 {
1091 space[x] += packing[y][x] ? 0 : 1;
1092 }
1093 }
1094
1095 int column = 0;
1096
1097 for (int x = 0; x < 4; x++)
1098 {
1099 if (space[x] > n && space[x] < space[column])
1100 {
1101 column = x;
1102 }
1103 }
1104
1105 if (space[column] > n)
1106 {
1107 for (int r = 0; r < MAX_VARYING_VECTORS; r++)
1108 {
1109 if (!packing[r][column])
1110 {
1111 varying->reg = r;
1112
1113 for (int y = r; y < r + n; y++)
1114 {
1115 packing[y][column] = &*varying;
1116 }
1117
1118 break;
1119 }
1120 }
1121
1122 varying->col = column;
1123
1124 success = true;
1125 }
1126 }
1127 else UNREACHABLE();
1128
1129 if (!success)
1130 {
1131 appendToInfoLog("Could not pack varying %s", varying->name.c_str());
1132
1133 return -1;
1134 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001135 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001136
1137 // Return the number of used registers
1138 int registers = 0;
1139
1140 for (int r = 0; r < MAX_VARYING_VECTORS; r++)
1141 {
1142 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1143 {
1144 registers++;
1145 }
1146 }
1147
1148 return registers;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001149}
1150
1151bool Program::linkVaryings()
1152{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001153 if (mPixelHLSL.empty() || mVertexHLSL.empty())
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001154 {
1155 return false;
1156 }
1157
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001158 const Varying *packing[MAX_VARYING_VECTORS][4] = {NULL};
1159 int registers = packVaryings(packing);
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001160
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001161 if (registers < 0)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001162 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001163 return false;
1164 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001165
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001166 if (registers == MAX_VARYING_VECTORS && mFragmentShader->mUsesFragCoord)
1167 {
1168 appendToInfoLog("No varying registers left to support gl_FragCoord");
1169
1170 return false;
1171 }
1172
1173 for (VaryingList::iterator input = mFragmentShader->varyings.begin(); input != mFragmentShader->varyings.end(); input++)
1174 {
1175 bool matched = false;
1176
1177 for (VaryingList::iterator output = mVertexShader->varyings.begin(); output != mVertexShader->varyings.end(); output++)
1178 {
1179 if (output->name == input->name)
1180 {
1181 if (output->type != input->type || output->size != input->size)
1182 {
1183 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
1184
1185 return false;
1186 }
1187
1188 output->reg = input->reg;
1189 output->col = input->col;
1190
1191 matched = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001192 break;
1193 }
1194 }
1195
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001196 if (!matched)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001197 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001198 appendToInfoLog("Fragment varying varying %s does not match any vertex varying", input->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001199
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001200 return false;
1201 }
1202 }
1203
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001204 Context *context = getContext();
1205 bool sm3 = context->supportsShaderModel3();
1206 std::string varyingSemantic = (sm3 ? "COLOR" : "TEXCOORD");
1207
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001208 mVertexHLSL += "struct VS_INPUT\n"
1209 "{\n";
1210
1211 int semanticIndex = 0;
1212 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1213 {
1214 switch (attribute->type)
1215 {
1216 case GL_FLOAT: mVertexHLSL += " float "; break;
1217 case GL_FLOAT_VEC2: mVertexHLSL += " float2 "; break;
1218 case GL_FLOAT_VEC3: mVertexHLSL += " float3 "; break;
1219 case GL_FLOAT_VEC4: mVertexHLSL += " float4 "; break;
1220 case GL_FLOAT_MAT2: mVertexHLSL += " float2x2 "; break;
1221 case GL_FLOAT_MAT3: mVertexHLSL += " float3x3 "; break;
1222 case GL_FLOAT_MAT4: mVertexHLSL += " float4x4 "; break;
1223 default: UNREACHABLE();
1224 }
1225
1226 mVertexHLSL += decorate(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1227
1228 semanticIndex += VariableRowCount(attribute->type);
1229 }
1230
1231 mVertexHLSL += "};\n"
1232 "\n"
1233 "struct VS_OUTPUT\n"
1234 "{\n"
1235 " float4 gl_Position : POSITION;\n";
1236
1237 for (int r = 0; r < registers; r++)
1238 {
1239 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1240
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001241 mVertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001242 }
1243
1244 if (mFragmentShader->mUsesFragCoord)
1245 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001246 mVertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1247 }
1248
1249 if (mVertexShader->mUsesPointSize && sm3)
1250 {
1251 mVertexHLSL += " float gl_PointSize : PSIZE;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001252 }
1253
1254 mVertexHLSL += "};\n"
1255 "\n"
1256 "VS_OUTPUT main(VS_INPUT input)\n"
1257 "{\n";
1258
1259 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1260 {
1261 mVertexHLSL += " " + decorate(attribute->name) + " = ";
1262
1263 if (VariableRowCount(attribute->type) > 1) // Matrix
1264 {
1265 mVertexHLSL += "transpose";
1266 }
1267
1268 mVertexHLSL += "(input." + decorate(attribute->name) + ");\n";
1269 }
1270
1271 mVertexHLSL += "\n"
1272 " gl_main();\n"
1273 "\n"
1274 " VS_OUTPUT output;\n"
1275 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
1276 " output.gl_Position.y = -(gl_Position.y - dx_HalfPixelSize.y * gl_Position.w);\n"
1277 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1278 " output.gl_Position.w = gl_Position.w;\n";
1279
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001280 if (mVertexShader->mUsesPointSize && sm3)
1281 {
1282 mVertexHLSL += " output.gl_PointSize = clamp(gl_PointSize, 1.0, " + str((int)ALIASED_POINT_SIZE_RANGE_MAX_SM3) + ");\n";
1283 }
1284
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001285 if (mFragmentShader->mUsesFragCoord)
1286 {
1287 mVertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1288 }
1289
1290 for (VaryingList::iterator varying = mVertexShader->varyings.begin(); varying != mVertexShader->varyings.end(); varying++)
1291 {
1292 if (varying->reg >= 0)
1293 {
1294 for (int i = 0; i < varying->size; i++)
1295 {
1296 int rows = VariableRowCount(varying->type);
1297
1298 for (int j = 0; j < rows; j++)
1299 {
1300 int r = varying->reg + i * rows + j;
1301 mVertexHLSL += " output.v" + str(r);
1302
1303 bool sharedRegister = false; // Register used by multiple varyings
1304
1305 for (int x = 0; x < 4; x++)
1306 {
1307 if (packing[r][x] && packing[r][x] != packing[r][0])
1308 {
1309 sharedRegister = true;
1310 break;
1311 }
1312 }
1313
1314 if(sharedRegister)
1315 {
1316 mVertexHLSL += ".";
1317
1318 for (int x = 0; x < 4; x++)
1319 {
1320 if (packing[r][x] == &*varying)
1321 {
1322 switch(x)
1323 {
1324 case 0: mVertexHLSL += "x"; break;
1325 case 1: mVertexHLSL += "y"; break;
1326 case 2: mVertexHLSL += "z"; break;
1327 case 3: mVertexHLSL += "w"; break;
1328 }
1329 }
1330 }
1331 }
1332
1333 mVertexHLSL += " = " + varying->name;
1334
1335 if (varying->array)
1336 {
1337 mVertexHLSL += "[" + str(i) + "]";
1338 }
1339
1340 if (rows > 1)
1341 {
1342 mVertexHLSL += "[" + str(j) + "]";
1343 }
1344
1345 mVertexHLSL += ";\n";
1346 }
1347 }
1348 }
1349 }
1350
1351 mVertexHLSL += "\n"
1352 " return output;\n"
1353 "}\n";
1354
1355 mPixelHLSL += "struct PS_INPUT\n"
1356 "{\n";
1357
1358 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1359 {
1360 if (varying->reg >= 0)
1361 {
1362 for (int i = 0; i < varying->size; i++)
1363 {
1364 int rows = VariableRowCount(varying->type);
1365 for (int j = 0; j < rows; j++)
1366 {
1367 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001368 mPixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001369 }
1370 }
1371 }
1372 else UNREACHABLE();
1373 }
1374
1375 if (mFragmentShader->mUsesFragCoord)
1376 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001377 mPixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001378 }
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001379
1380 if (mFragmentShader->mUsesPointCoord && sm3)
1381 {
1382 mPixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1383 }
1384
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001385 if (mFragmentShader->mUsesFrontFacing)
1386 {
1387 mPixelHLSL += " float vFace : VFACE;\n";
1388 }
1389
1390 mPixelHLSL += "};\n"
1391 "\n"
1392 "struct PS_OUTPUT\n"
1393 "{\n"
1394 " float4 gl_Color[1] : COLOR;\n"
1395 "};\n"
1396 "\n"
1397 "PS_OUTPUT main(PS_INPUT input)\n"
1398 "{\n";
1399
1400 if (mFragmentShader->mUsesFragCoord)
1401 {
1402 mPixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n"
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00001403 " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Viewport.x + dx_Viewport.z;\n"
1404 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Viewport.y + dx_Viewport.w;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001405 " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
1406 " gl_FragCoord.w = rhw;\n";
1407 }
1408
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001409 if (mFragmentShader->mUsesPointCoord && sm3)
1410 {
1411 mPixelHLSL += " gl_PointCoord = float2(input.gl_PointCoord.x, 1.0 - input.gl_PointCoord.y);\n";
1412 }
1413
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001414 if (mFragmentShader->mUsesFrontFacing)
1415 {
1416 mPixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1417 }
1418
1419 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1420 {
1421 if (varying->reg >= 0)
1422 {
1423 for (int i = 0; i < varying->size; i++)
1424 {
1425 int rows = VariableRowCount(varying->type);
1426 for (int j = 0; j < rows; j++)
1427 {
1428 std::string n = str(varying->reg + i * rows + j);
1429 mPixelHLSL += " " + varying->name;
1430
1431 if (varying->array)
1432 {
1433 mPixelHLSL += "[" + str(i) + "]";
1434 }
1435
1436 if (rows > 1)
1437 {
1438 mPixelHLSL += "[" + str(j) + "]";
1439 }
1440
1441 mPixelHLSL += " = input.v" + n + ";\n";
1442 }
1443 }
1444 }
1445 else UNREACHABLE();
1446 }
1447
1448 mPixelHLSL += "\n"
1449 " gl_main();\n"
1450 "\n"
1451 " PS_OUTPUT output;\n"
1452 " output.gl_Color[0] = gl_Color[0];\n"
1453 "\n"
1454 " return output;\n"
1455 "}\n";
1456
1457 TRACE("\n%s", mPixelHLSL.c_str());
1458 TRACE("\n%s", mVertexHLSL.c_str());
1459
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001460 return true;
1461}
1462
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001463// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1464// compiling them into binaries, determining the attribute mappings, and collecting
1465// a list of uniforms
1466void Program::link()
1467{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001468 unlink();
1469
1470 if (!mFragmentShader || !mFragmentShader->isCompiled())
1471 {
1472 return;
1473 }
1474
1475 if (!mVertexShader || !mVertexShader->isCompiled())
1476 {
1477 return;
1478 }
1479
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001480 mPixelHLSL = mFragmentShader->getHLSL();
1481 mVertexHLSL = mVertexShader->getHLSL();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001482
1483 if (!linkVaryings())
1484 {
1485 return;
1486 }
1487
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001488 Context *context = getContext();
1489 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1490 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1491
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001492 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1493 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001494
1495 if (vertexBinary && pixelBinary)
1496 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001497 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001498 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1499 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1500
1501 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1502 {
1503 return error(GL_OUT_OF_MEMORY);
1504 }
1505
1506 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001507
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001508 vertexBinary->Release();
1509 pixelBinary->Release();
1510 vertexBinary = NULL;
1511 pixelBinary = NULL;
1512
1513 if (mVertexExecutable && mPixelExecutable)
1514 {
1515 if (!linkAttributes())
1516 {
1517 return;
1518 }
1519
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001520 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001521 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001522 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001523 }
1524
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001525 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001526 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001527 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001528 }
1529
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001530 // these uniforms are searched as already-decorated because gl_ and dx_
1531 // are reserved prefixes, and do not receive additional decoration
1532 mDepthRangeNearLocation = getUniformLocation("gl_DepthRange.near", true);
1533 mDepthRangeFarLocation = getUniformLocation("gl_DepthRange.far", true);
1534 mDepthRangeDiffLocation = getUniformLocation("gl_DepthRange.diff", true);
1535 mDxDepthLocation = getUniformLocation("dx_Depth", true);
daniel@transgaming.com162267d2010-07-28 19:20:48 +00001536 mDxViewportLocation = getUniformLocation("dx_Viewport", true);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001537 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize", true);
1538 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW", true);
1539 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines", true);
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00001540
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001541 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001542 }
1543 }
1544}
1545
1546// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1547bool Program::linkAttributes()
1548{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001549 unsigned int usedLocations = 0;
1550
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001551 // Link attributes that have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001552 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001553 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001554 int location = getAttributeBinding(attribute->name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001555
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001556 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001557 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001558 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001559 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001560 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001561 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001562
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001563 mLinkedAttribute[location] = *attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001564
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001565 int rows = VariableRowCount(attribute->type);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001566
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001567 if (rows + location > MAX_VERTEX_ATTRIBS)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001568 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001569 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 +00001570
1571 return false;
1572 }
1573
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001574 for (int i = 0; i < rows; i++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001575 {
1576 usedLocations |= 1 << (location + i);
1577 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001578 }
1579 }
1580
1581 // Link attributes that don't have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001582 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001583 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001584 int location = getAttributeBinding(attribute->name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001585
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001586 if (location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001587 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001588 int rows = VariableRowCount(attribute->type);
1589 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001590
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001591 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001592 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001593 appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001594
1595 return false; // Fail to link
1596 }
1597
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001598 mLinkedAttribute[availableIndex] = *attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001599 }
1600 }
1601
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001602 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001603 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001604 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001605 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001606
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001607 for (int r = 0; r < rows; r++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001608 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001609 mSemanticIndex[attributeIndex++] = index++;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001610 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001611 }
1612
1613 return true;
1614}
1615
daniel@transgaming.com85423182010-04-22 13:35:27 +00001616int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001617{
1618 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1619 {
1620 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1621 {
1622 return location;
1623 }
1624 }
1625
1626 return -1;
1627}
1628
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001629bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1630{
1631 D3DXCONSTANTTABLE_DESC constantTableDescription;
1632 D3DXCONSTANT_DESC constantDescription;
1633 UINT descriptionCount = 1;
1634
1635 constantTable->GetDesc(&constantTableDescription);
1636
1637 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1638 {
1639 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1640 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1641
1642 if (!defineUniform(constantHandle, constantDescription))
1643 {
1644 return false;
1645 }
1646 }
1647
1648 return true;
1649}
1650
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001651// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001652// Returns true if succesful (uniform not already defined)
1653bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1654{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001655 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1656 {
1657 unsigned int samplerIndex = constantDescription.RegisterIndex;
1658
1659 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1660
1661 mSamplers[samplerIndex].active = true;
1662 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1663 mSamplers[samplerIndex].logicalTextureUnit = 0;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001664 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001665 }
1666
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001667 switch(constantDescription.Class)
1668 {
1669 case D3DXPC_STRUCT:
1670 {
1671 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1672 {
1673 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1674
1675 D3DXCONSTANT_DESC fieldDescription;
1676 UINT descriptionCount = 1;
1677
1678 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1679
1680 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1681 {
1682 return false;
1683 }
1684 }
1685
1686 return true;
1687 }
1688 case D3DXPC_SCALAR:
1689 case D3DXPC_VECTOR:
1690 case D3DXPC_MATRIX_COLUMNS:
1691 case D3DXPC_OBJECT:
1692 return defineUniform(constantDescription, name + constantDescription.Name);
1693 default:
1694 UNREACHABLE();
1695 return false;
1696 }
1697}
1698
1699bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1700{
1701 Uniform *uniform = createUniform(constantDescription, name);
1702
1703 if(!uniform)
1704 {
1705 return false;
1706 }
1707
1708 // Check if already defined
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001709 GLint location = getUniformLocation(name.c_str(), true);
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001710 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001711
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001712 if (location >= 0)
1713 {
1714 delete uniform;
1715
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001716 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001717 {
1718 return false;
1719 }
1720 else
1721 {
1722 return true;
1723 }
1724 }
1725
1726 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001727 unsigned int uniformIndex = mUniforms.size() - 1;
1728
1729 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1730 {
1731 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1732 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001733
1734 return true;
1735}
1736
1737Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001738{
1739 if (constantDescription.Rows == 1) // Vectors and scalars
1740 {
1741 switch (constantDescription.Type)
1742 {
1743 case D3DXPT_SAMPLER2D:
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001744 switch (constantDescription.Columns)
1745 {
1746 case 1: return new Uniform(GL_SAMPLER_2D, name, constantDescription.Elements);
1747 default: UNREACHABLE();
1748 }
1749 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001750 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001751 switch (constantDescription.Columns)
1752 {
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001753 case 1: return new Uniform(GL_SAMPLER_CUBE, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001754 default: UNREACHABLE();
1755 }
1756 break;
1757 case D3DXPT_BOOL:
1758 switch (constantDescription.Columns)
1759 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001760 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1761 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1762 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1763 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001764 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001765 }
1766 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001767 case D3DXPT_INT:
1768 switch (constantDescription.Columns)
1769 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001770 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1771 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1772 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1773 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001774 default: UNREACHABLE();
1775 }
1776 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001777 case D3DXPT_FLOAT:
1778 switch (constantDescription.Columns)
1779 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001780 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1781 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1782 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1783 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001784 default: UNREACHABLE();
1785 }
1786 break;
1787 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001788 UNREACHABLE();
1789 }
1790 }
1791 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1792 {
1793 switch (constantDescription.Type)
1794 {
1795 case D3DXPT_FLOAT:
1796 switch (constantDescription.Rows)
1797 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001798 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1799 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1800 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001801 default: UNREACHABLE();
1802 }
1803 break;
1804 default: UNREACHABLE();
1805 }
1806 }
1807 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001808
1809 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001810}
1811
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001812// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001813std::string Program::decorate(const std::string &string)
1814{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001815 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001816 {
1817 return "_" + string;
1818 }
1819 else
1820 {
1821 return string;
1822 }
1823}
1824
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001825std::string Program::undecorate(const std::string &string)
1826{
1827 if (string.substr(0, 1) == "_")
1828 {
1829 return string.substr(1);
1830 }
1831 else
1832 {
1833 return string;
1834 }
1835}
1836
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001837bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1838{
1839 BOOL *vector = new BOOL[count];
1840 for (int i = 0; i < count; i++)
1841 {
1842 if (v[i] == GL_FALSE)
1843 vector[i] = 0;
1844 else
1845 vector[i] = 1;
1846 }
1847
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001848 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1849
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001850 D3DXHANDLE constantPS;
1851 D3DXHANDLE constantVS;
1852 getConstantHandles(targetUniform, &constantPS, &constantVS);
1853
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001854 IDirect3DDevice9 *device = getDevice();
1855
1856 if (constantPS)
1857 {
1858 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1859 }
1860
1861 if (constantVS)
1862 {
1863 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1864 }
1865
1866 delete [] vector;
1867
1868 return true;
1869}
1870
1871bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1872{
1873 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1874
1875 for (int i = 0; i < count; i++)
1876 {
1877 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1878 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1879
1880 v += 2;
1881 }
1882
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001883 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1884
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001885 D3DXHANDLE constantPS;
1886 D3DXHANDLE constantVS;
1887 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001888 IDirect3DDevice9 *device = getDevice();
1889
1890 if (constantPS)
1891 {
1892 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1893 }
1894
1895 if (constantVS)
1896 {
1897 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1898 }
1899
1900 delete[] vector;
1901
1902 return true;
1903}
1904
1905bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1906{
1907 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1908
1909 for (int i = 0; i < count; i++)
1910 {
1911 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1912 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1913 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1914
1915 v += 3;
1916 }
1917
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001918 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1919
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001920 D3DXHANDLE constantPS;
1921 D3DXHANDLE constantVS;
1922 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001923 IDirect3DDevice9 *device = getDevice();
1924
1925 if (constantPS)
1926 {
1927 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1928 }
1929
1930 if (constantVS)
1931 {
1932 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1933 }
1934
1935 delete[] vector;
1936
1937 return true;
1938}
1939
1940bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1941{
1942 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1943
1944 for (int i = 0; i < count; i++)
1945 {
1946 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1947 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1948 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1949 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1950
1951 v += 3;
1952 }
1953
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001954 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1955
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001956 D3DXHANDLE constantPS;
1957 D3DXHANDLE constantVS;
1958 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001959 IDirect3DDevice9 *device = getDevice();
1960
1961 if (constantPS)
1962 {
1963 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1964 }
1965
1966 if (constantVS)
1967 {
1968 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1969 }
1970
1971 delete [] vector;
1972
1973 return true;
1974}
1975
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001976bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1977{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001978 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1979
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001980 D3DXHANDLE constantPS;
1981 D3DXHANDLE constantVS;
1982 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001983 IDirect3DDevice9 *device = getDevice();
1984
1985 if (constantPS)
1986 {
1987 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1988 }
1989
1990 if (constantVS)
1991 {
1992 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1993 }
1994
1995 return true;
1996}
1997
1998bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1999{
2000 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2001
2002 for (int i = 0; i < count; i++)
2003 {
2004 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
2005
2006 v += 2;
2007 }
2008
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002009 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2010
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002011 D3DXHANDLE constantPS;
2012 D3DXHANDLE constantVS;
2013 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002014 IDirect3DDevice9 *device = getDevice();
2015
2016 if (constantPS)
2017 {
2018 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2019 }
2020
2021 if (constantVS)
2022 {
2023 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2024 }
2025
2026 delete[] vector;
2027
2028 return true;
2029}
2030
2031bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
2032{
2033 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2034
2035 for (int i = 0; i < count; i++)
2036 {
2037 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
2038
2039 v += 3;
2040 }
2041
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002042 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2043
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002044 D3DXHANDLE constantPS;
2045 D3DXHANDLE constantVS;
2046 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002047 IDirect3DDevice9 *device = getDevice();
2048
2049 if (constantPS)
2050 {
2051 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2052 }
2053
2054 if (constantVS)
2055 {
2056 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2057 }
2058
2059 delete[] vector;
2060
2061 return true;
2062}
2063
2064bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
2065{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002066 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2067
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002068 D3DXHANDLE constantPS;
2069 D3DXHANDLE constantVS;
2070 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002071 IDirect3DDevice9 *device = getDevice();
2072
2073 if (constantPS)
2074 {
2075 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
2076 }
2077
2078 if (constantVS)
2079 {
2080 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
2081 }
2082
2083 return true;
2084}
2085
2086bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
2087{
2088 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2089
2090 for (int i = 0; i < count; i++)
2091 {
2092 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
2093 value[1], value[3], 0, 0,
2094 0, 0, 1, 0,
2095 0, 0, 0, 1);
2096
2097 value += 4;
2098 }
2099
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002100 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2101
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002102 D3DXHANDLE constantPS;
2103 D3DXHANDLE constantVS;
2104 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002105 IDirect3DDevice9 *device = getDevice();
2106
2107 if (constantPS)
2108 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002109 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002110 }
2111
2112 if (constantVS)
2113 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002114 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002115 }
2116
2117 delete[] matrix;
2118
2119 return true;
2120}
2121
2122bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
2123{
2124 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2125
2126 for (int i = 0; i < count; i++)
2127 {
2128 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
2129 value[1], value[4], value[7], 0,
2130 value[2], value[5], value[8], 0,
2131 0, 0, 0, 1);
2132
2133 value += 9;
2134 }
2135
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002136 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2137
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002138 D3DXHANDLE constantPS;
2139 D3DXHANDLE constantVS;
2140 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002141 IDirect3DDevice9 *device = getDevice();
2142
2143 if (constantPS)
2144 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002145 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002146 }
2147
2148 if (constantVS)
2149 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002150 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002151 }
2152
2153 delete[] matrix;
2154
2155 return true;
2156}
2157
2158bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
2159{
2160 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2161
2162 for (int i = 0; i < count; i++)
2163 {
2164 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
2165 value[1], value[5], value[9], value[13],
2166 value[2], value[6], value[10], value[14],
2167 value[3], value[7], value[11], value[15]);
2168
2169 value += 16;
2170 }
2171
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002172 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2173
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002174 D3DXHANDLE constantPS;
2175 D3DXHANDLE constantVS;
2176 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002177 IDirect3DDevice9 *device = getDevice();
2178
2179 if (constantPS)
2180 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002181 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002182 }
2183
2184 if (constantVS)
2185 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002186 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002187 }
2188
2189 delete[] matrix;
2190
2191 return true;
2192}
2193
2194bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
2195{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002196 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2197
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002198 D3DXHANDLE constantPS;
2199 D3DXHANDLE constantVS;
2200 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002201 IDirect3DDevice9 *device = getDevice();
2202
2203 if (constantPS)
2204 {
2205 D3DXCONSTANT_DESC constantDescription;
2206 UINT descriptionCount = 1;
2207 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
2208
daniel@transgaming.com2884b782010-03-08 21:30:48 +00002209 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002210 {
2211 return false;
2212 }
2213
2214 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2215 {
2216 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
2217
2218 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
2219 {
2220 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002221
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002222 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002223 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002224 ASSERT(mSamplers[samplerIndex].active);
2225 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
2226 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002227 }
2228 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002229
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002230 return true;
2231 }
2232 }
2233
2234 if (constantPS)
2235 {
2236 mConstantTablePS->SetIntArray(device, constantPS, v, count);
2237 }
2238
2239 if (constantVS)
2240 {
2241 mConstantTableVS->SetIntArray(device, constantVS, v, count);
2242 }
2243
2244 return true;
2245}
2246
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002247bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
2248{
2249 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2250
2251 for (int i = 0; i < count; i++)
2252 {
2253 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2254
2255 v += 2;
2256 }
2257
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002258 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2259
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002260 D3DXHANDLE constantPS;
2261 D3DXHANDLE constantVS;
2262 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002263 IDirect3DDevice9 *device = getDevice();
2264
2265 if (constantPS)
2266 {
2267 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2268 }
2269
2270 if (constantVS)
2271 {
2272 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2273 }
2274
2275 delete[] vector;
2276
2277 return true;
2278}
2279
2280bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
2281{
2282 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2283
2284 for (int i = 0; i < count; i++)
2285 {
2286 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2287
2288 v += 3;
2289 }
2290
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002291 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2292
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002293 D3DXHANDLE constantPS;
2294 D3DXHANDLE constantVS;
2295 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002296 IDirect3DDevice9 *device = getDevice();
2297
2298 if (constantPS)
2299 {
2300 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2301 }
2302
2303 if (constantVS)
2304 {
2305 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2306 }
2307
2308 delete[] vector;
2309
2310 return true;
2311}
2312
2313bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
2314{
2315 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2316
2317 for (int i = 0; i < count; i++)
2318 {
2319 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2320
2321 v += 4;
2322 }
2323
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002324 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2325
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002326 D3DXHANDLE constantPS;
2327 D3DXHANDLE constantVS;
2328 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002329 IDirect3DDevice9 *device = getDevice();
2330
2331 if (constantPS)
2332 {
2333 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2334 }
2335
2336 if (constantVS)
2337 {
2338 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2339 }
2340
2341 delete [] vector;
2342
2343 return true;
2344}
2345
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002346void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002347{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002348 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002349 {
2350 return;
2351 }
2352
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002353 char info[1024];
2354
2355 va_list vararg;
2356 va_start(vararg, format);
2357 vsnprintf(info, sizeof(info), format, vararg);
2358 va_end(vararg);
2359
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002360 size_t infoLength = strlen(info);
2361
2362 if (!mInfoLog)
2363 {
2364 mInfoLog = new char[infoLength + 1];
2365 strcpy(mInfoLog, info);
2366 }
2367 else
2368 {
2369 size_t logLength = strlen(mInfoLog);
2370 char *newLog = new char[logLength + infoLength + 1];
2371 strcpy(newLog, mInfoLog);
2372 strcpy(newLog + logLength, info);
2373
2374 delete[] mInfoLog;
2375 mInfoLog = newLog;
2376 }
2377}
2378
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002379void Program::resetInfoLog()
2380{
2381 if (mInfoLog)
2382 {
2383 delete [] mInfoLog;
daniel@transgaming.com6a20d102010-08-31 13:54:27 +00002384 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002385 }
2386}
2387
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002388// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
2389void Program::unlink(bool destroy)
2390{
2391 if (destroy) // Object being destructed
2392 {
2393 if (mFragmentShader)
2394 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002395 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002396 mFragmentShader = NULL;
2397 }
2398
2399 if (mVertexShader)
2400 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002401 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002402 mVertexShader = NULL;
2403 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002404 }
2405
2406 if (mPixelExecutable)
2407 {
2408 mPixelExecutable->Release();
2409 mPixelExecutable = NULL;
2410 }
2411
2412 if (mVertexExecutable)
2413 {
2414 mVertexExecutable->Release();
2415 mVertexExecutable = NULL;
2416 }
2417
2418 if (mConstantTablePS)
2419 {
2420 mConstantTablePS->Release();
2421 mConstantTablePS = NULL;
2422 }
2423
2424 if (mConstantTableVS)
2425 {
2426 mConstantTableVS->Release();
2427 mConstantTableVS = NULL;
2428 }
2429
2430 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2431 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002432 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002433 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002434 }
2435
2436 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2437 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00002438 mSamplers[index].active = false;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00002439 mSamplers[index].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002440 }
2441
2442 while (!mUniforms.empty())
2443 {
2444 delete mUniforms.back();
2445 mUniforms.pop_back();
2446 }
2447
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002448 mDepthRangeDiffLocation = -1;
2449 mDepthRangeNearLocation = -1;
2450 mDepthRangeFarLocation = -1;
2451 mDxDepthLocation = -1;
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002452 mDxViewportLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002453 mDxHalfPixelSizeLocation = -1;
2454 mDxFrontCCWLocation = -1;
2455 mDxPointsOrLinesLocation = -1;
2456
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002457 mUniformIndex.clear();
2458
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002459 mPixelHLSL.clear();
2460 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002461
2462 delete[] mInfoLog;
2463 mInfoLog = NULL;
2464
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002465 mLinked = false;
2466}
2467
2468bool Program::isLinked()
2469{
2470 return mLinked;
2471}
2472
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002473bool Program::isValidated() const
2474{
2475 return mValidated;
2476}
2477
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002478void Program::release()
2479{
2480 mRefCount--;
2481
2482 if (mRefCount == 0 && mDeleteStatus)
2483 {
2484 mResourceManager->deleteProgram(mHandle);
2485 }
2486}
2487
2488void Program::addRef()
2489{
2490 mRefCount++;
2491}
2492
2493unsigned int Program::getRefCount() const
2494{
2495 return mRefCount;
2496}
2497
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002498unsigned int Program::getSerial() const
2499{
2500 return mSerial;
2501}
2502
2503unsigned int Program::issueSerial()
2504{
2505 return mCurrentSerial++;
2506}
2507
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002508int Program::getInfoLogLength() const
2509{
2510 if (!mInfoLog)
2511 {
2512 return 0;
2513 }
2514 else
2515 {
2516 return strlen(mInfoLog) + 1;
2517 }
2518}
2519
2520void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2521{
2522 int index = 0;
2523
2524 if (mInfoLog)
2525 {
2526 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2527 {
2528 infoLog[index] = mInfoLog[index];
2529 index++;
2530 }
2531 }
2532
2533 if (bufSize)
2534 {
2535 infoLog[index] = '\0';
2536 }
2537
2538 if (length)
2539 {
2540 *length = index;
2541 }
2542}
2543
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002544void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2545{
2546 int total = 0;
2547
2548 if (mVertexShader)
2549 {
2550 if (total < maxCount)
2551 {
2552 shaders[total] = mVertexShader->getHandle();
2553 }
2554
2555 total++;
2556 }
2557
2558 if (mFragmentShader)
2559 {
2560 if (total < maxCount)
2561 {
2562 shaders[total] = mFragmentShader->getHandle();
2563 }
2564
2565 total++;
2566 }
2567
2568 if (count)
2569 {
2570 *count = total;
2571 }
2572}
2573
daniel@transgaming.com85423182010-04-22 13:35:27 +00002574void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2575{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002576 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002577 for (unsigned int i = 0; i < index; i++)
2578 {
2579 do
2580 {
2581 attribute++;
2582
2583 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2584 }
2585 while (mLinkedAttribute[attribute].name.empty());
2586 }
2587
2588 if (bufsize > 0)
2589 {
2590 const char *string = mLinkedAttribute[attribute].name.c_str();
2591
2592 strncpy(name, string, bufsize);
2593 name[bufsize - 1] = '\0';
2594
2595 if (length)
2596 {
2597 *length = strlen(name);
2598 }
2599 }
2600
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002601 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002602
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002603 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002604}
2605
2606GLint Program::getActiveAttributeCount()
2607{
2608 int count = 0;
2609
2610 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2611 {
2612 if (!mLinkedAttribute[attributeIndex].name.empty())
2613 {
2614 count++;
2615 }
2616 }
2617
2618 return count;
2619}
2620
2621GLint Program::getActiveAttributeMaxLength()
2622{
2623 int maxLength = 0;
2624
2625 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2626 {
2627 if (!mLinkedAttribute[attributeIndex].name.empty())
2628 {
2629 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2630 }
2631 }
2632
2633 return maxLength;
2634}
2635
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002636void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2637{
2638 unsigned int uniform = 0;
2639 for (unsigned int i = 0; i < index; i++)
2640 {
2641 do
2642 {
2643 uniform++;
2644
2645 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2646 }
2647 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2648 }
2649
2650 if (bufsize > 0)
2651 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002652 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002653
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002654 if (mUniforms[uniform]->arraySize != 1)
2655 {
2656 string += "[0]";
2657 }
2658
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002659 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002660 name[bufsize - 1] = '\0';
2661
2662 if (length)
2663 {
2664 *length = strlen(name);
2665 }
2666 }
2667
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002668 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002669
2670 *type = mUniforms[uniform]->type;
2671}
2672
2673GLint Program::getActiveUniformCount()
2674{
2675 int count = 0;
2676
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002677 unsigned int numUniforms = mUniforms.size();
2678 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002679 {
2680 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2681 {
2682 count++;
2683 }
2684 }
2685
2686 return count;
2687}
2688
2689GLint Program::getActiveUniformMaxLength()
2690{
2691 int maxLength = 0;
2692
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002693 unsigned int numUniforms = mUniforms.size();
2694 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002695 {
2696 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2697 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002698 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002699 }
2700 }
2701
2702 return maxLength;
2703}
2704
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002705void Program::flagForDeletion()
2706{
2707 mDeleteStatus = true;
2708}
2709
2710bool Program::isFlaggedForDeletion() const
2711{
2712 return mDeleteStatus;
2713}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002714
2715void Program::validate()
2716{
2717 resetInfoLog();
2718
2719 if (!isLinked())
2720 {
2721 appendToInfoLog("Program has not been successfully linked.");
2722 mValidated = false;
2723 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002724 else
2725 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002726 applyUniforms();
2727 if (!validateSamplers())
2728 {
2729 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2730 mValidated = false;
2731 }
2732 else
2733 {
2734 mValidated = true;
2735 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002736 }
2737}
2738
2739bool Program::validateSamplers() const
2740{
2741 // if any two active samplers in a program are of different types, but refer to the same
2742 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2743 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2744 std::map<int, SamplerType> samplerMap;
2745 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2746 {
2747 if (mSamplers[i].active)
2748 {
2749 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2750 {
2751 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2752 return false;
2753 }
2754 else
2755 {
2756 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2757 }
2758 }
2759 }
2760
2761 return true;
2762}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002763
2764void Program::getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS)
2765{
2766 if (!targetUniform->handlesSet)
2767 {
2768 targetUniform->psHandle = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2769 targetUniform->vsHandle = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
2770 targetUniform->handlesSet = true;
2771 }
2772
2773 *constantPS = targetUniform->psHandle;
2774 *constantVS = targetUniform->vsHandle;
2775}
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002776
2777GLint Program::getDepthRangeDiffLocation() const
2778{
2779 return mDepthRangeDiffLocation;
2780}
2781
2782GLint Program::getDepthRangeNearLocation() const
2783{
daniel@transgaming.come0d7d432010-05-18 18:51:52 +00002784 return mDepthRangeNearLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002785}
2786
2787GLint Program::getDepthRangeFarLocation() const
2788{
2789 return mDepthRangeFarLocation;
2790}
2791
2792GLint Program::getDxDepthLocation() const
2793{
2794 return mDxDepthLocation;
2795}
2796
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002797GLint Program::getDxViewportLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002798{
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002799 return mDxViewportLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002800}
2801
2802GLint Program::getDxHalfPixelSizeLocation() const
2803{
2804 return mDxHalfPixelSizeLocation;
2805}
2806
2807GLint Program::getDxFrontCCWLocation() const
2808{
2809 return mDxFrontCCWLocation;
2810}
2811
2812GLint Program::getDxPointsOrLinesLocation() const
2813{
2814 return mDxPointsOrLinesLocation;
2815}
2816
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002817}