blob: c5e75056fee8052fcfaa7e19b396646cba53eb66 [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.com73a5db62010-10-15 17:58:13 +000048Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial())
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;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000066}
67
68Program::~Program()
69{
70 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000071
72 if (mVertexShader != NULL)
73 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000074 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000075 }
76
77 if (mFragmentShader != NULL)
78 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000079 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000080 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000081}
82
83bool Program::attachShader(Shader *shader)
84{
85 if (shader->getType() == GL_VERTEX_SHADER)
86 {
87 if (mVertexShader)
88 {
89 return false;
90 }
91
92 mVertexShader = (VertexShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000093 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000094 }
95 else if (shader->getType() == GL_FRAGMENT_SHADER)
96 {
97 if (mFragmentShader)
98 {
99 return false;
100 }
101
102 mFragmentShader = (FragmentShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000103 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000104 }
105 else UNREACHABLE();
106
107 return true;
108}
109
110bool Program::detachShader(Shader *shader)
111{
112 if (shader->getType() == GL_VERTEX_SHADER)
113 {
114 if (mVertexShader != shader)
115 {
116 return false;
117 }
118
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000119 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000120 mVertexShader = NULL;
121 }
122 else if (shader->getType() == GL_FRAGMENT_SHADER)
123 {
124 if (mFragmentShader != shader)
125 {
126 return false;
127 }
128
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000129 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000130 mFragmentShader = NULL;
131 }
132 else UNREACHABLE();
133
134 unlink();
135
136 return true;
137}
138
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000139int Program::getAttachedShadersCount() const
140{
141 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
142}
143
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144IDirect3DPixelShader9 *Program::getPixelShader()
145{
146 return mPixelExecutable;
147}
148
149IDirect3DVertexShader9 *Program::getVertexShader()
150{
151 return mVertexExecutable;
152}
153
154void Program::bindAttributeLocation(GLuint index, const char *name)
155{
156 if (index < MAX_VERTEX_ATTRIBS)
157 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000158 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
159 {
160 mAttributeBinding[i].erase(name);
161 }
162
163 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164 }
165}
166
167GLuint Program::getAttributeLocation(const char *name)
168{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000169 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000170 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000171 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000172 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000173 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000174 {
175 return index;
176 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177 }
178 }
179
180 return -1;
181}
182
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000183int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184{
185 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
186 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000187 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000188 }
189
190 return -1;
191}
192
193// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
194// index referenced in the compiled HLSL shader
195GLint Program::getSamplerMapping(unsigned int samplerIndex)
196{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000197 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
198
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000199 GLint logicalTextureUnit = -1;
200
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000201 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000202 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000203 logicalTextureUnit = mSamplers[samplerIndex].logicalTextureUnit;
204 }
205
206 if (logicalTextureUnit < MAX_TEXTURE_IMAGE_UNITS)
207 {
208 return logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000209 }
210
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000211 return -1;
212}
213
214SamplerType Program::getSamplerType(unsigned int samplerIndex)
215{
216 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
217 assert(mSamplers[samplerIndex].active);
218
219 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000220}
221
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000222bool Program::isSamplerDirty(unsigned int samplerIndex) const
223{
224 if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]))
225 {
226 return mSamplers[samplerIndex].dirty;
227 }
228 else UNREACHABLE();
229
230 return false;
231}
232
233void Program::setSamplerDirty(unsigned int samplerIndex, bool dirty)
234{
235 if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]))
236 {
237 mSamplers[samplerIndex].dirty = dirty;
238 }
239 else UNREACHABLE();
240}
241
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000242GLint Program::getUniformLocation(const char *name, bool decorated)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000243{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000244 std::string nameStr(name);
245 int subscript = 0;
246 size_t beginB = nameStr.find('[');
247 size_t endB = nameStr.find(']');
248 if (beginB != std::string::npos && endB != std::string::npos)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000249 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000250 std::string subscrStr = nameStr.substr(beginB + 1, beginB - endB - 1);
251 nameStr.erase(beginB);
252 subscript = atoi(subscrStr.c_str());
253 }
254
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000255 if (!decorated)
256 {
257 nameStr = decorate(nameStr);
258 }
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000259
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000260 unsigned int numUniforms = mUniformIndex.size();
261 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000262 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000263 if (mUniformIndex[location].name == nameStr &&
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000264 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000265 {
266 return location;
267 }
268 }
269
270 return -1;
271}
272
273bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
274{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000275 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000276 {
277 return false;
278 }
279
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000280 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000281 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000282
283 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000284 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000285 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000286
287 if (arraySize == 1 && count > 1)
288 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
289
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000290 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000291
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000292 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
293 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000294 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000295 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000296 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000297 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000298
299 if (arraySize == 1 && count > 1)
300 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000301
302 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000303 GLboolean *boolParams = new GLboolean[count];
304
305 for (int i = 0; i < count; ++i)
306 {
307 if (v[i] == 0.0f)
308 {
309 boolParams[i] = GL_FALSE;
310 }
311 else
312 {
313 boolParams[i] = GL_TRUE;
314 }
315 }
316
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000317 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
318 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000319
320 delete [] boolParams;
321 }
322 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000323 {
324 return false;
325 }
326
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000327 return true;
328}
329
330bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
331{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000332 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000333 {
334 return false;
335 }
336
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000337 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000338 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000339
340 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000341 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000342 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000343
344 if (arraySize == 1 && count > 1)
345 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
346
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000347 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000348
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000349 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
350 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000351 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000352 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000353 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000354 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000355
356 if (arraySize == 1 && count > 1)
357 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
358
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000359 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
360
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000361 GLboolean *boolParams = new GLboolean[count * 2];
362
363 for (int i = 0; i < count * 2; ++i)
364 {
365 if (v[i] == 0.0f)
366 {
367 boolParams[i] = GL_FALSE;
368 }
369 else
370 {
371 boolParams[i] = GL_TRUE;
372 }
373 }
374
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000375 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
376 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000377
378 delete [] boolParams;
379 }
380 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000381 {
382 return false;
383 }
384
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000385 return true;
386}
387
388bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
389{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000390 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000391 {
392 return false;
393 }
394
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000395 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000396 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000397
398 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000399 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000400 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000401
402 if (arraySize == 1 && count > 1)
403 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
404
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000405 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000406
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000407 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
408 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000409 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000410 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000411 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000412 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000413
414 if (arraySize == 1 && count > 1)
415 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
416
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000417 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000418 GLboolean *boolParams = new GLboolean[count * 3];
419
420 for (int i = 0; i < count * 3; ++i)
421 {
422 if (v[i] == 0.0f)
423 {
424 boolParams[i] = GL_FALSE;
425 }
426 else
427 {
428 boolParams[i] = GL_TRUE;
429 }
430 }
431
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000432 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
433 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000434
435 delete [] boolParams;
436 }
437 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000438 {
439 return false;
440 }
441
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442 return true;
443}
444
445bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
446{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000447 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 {
449 return false;
450 }
451
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000452 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000453 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000454
455 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000456 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000457 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000458
459 if (arraySize == 1 && count > 1)
460 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
461
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000462 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000463
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000464 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
465 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000466 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000467 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000468 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000469 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000470
471 if (arraySize == 1 && count > 1)
472 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
473
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000474 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000475 GLboolean *boolParams = new GLboolean[count * 4];
476
477 for (int i = 0; i < count * 4; ++i)
478 {
479 if (v[i] == 0.0f)
480 {
481 boolParams[i] = GL_FALSE;
482 }
483 else
484 {
485 boolParams[i] = GL_TRUE;
486 }
487 }
488
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000489 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
490 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000491
492 delete [] boolParams;
493 }
494 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000495 {
496 return false;
497 }
498
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000499 return true;
500}
501
502bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
503{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000504 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000505 {
506 return false;
507 }
508
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000509 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000510 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000511
512 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000513 {
514 return false;
515 }
516
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000517 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000518
519 if (arraySize == 1 && count > 1)
520 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
521
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000522 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000523
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000524 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
525 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000526
527 return true;
528}
529
530bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
531{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000532 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000533 {
534 return false;
535 }
536
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000537 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000538 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000539
540 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000541 {
542 return false;
543 }
544
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000545 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000546
547 if (arraySize == 1 && count > 1)
548 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
549
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000550 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000551
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000552 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
553 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000554
555 return true;
556}
557
558bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
559{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000560 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000561 {
562 return false;
563 }
564
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000565 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000566 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000567
568 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000569 {
570 return false;
571 }
572
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000573 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000574
575 if (arraySize == 1 && count > 1)
576 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
577
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000578 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000579
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000580 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
581 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000582
583 return true;
584}
585
586bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
587{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000588 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000589 {
590 return false;
591 }
592
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000593 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000594 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000595
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000596 if (targetUniform->type == GL_INT ||
597 targetUniform->type == GL_SAMPLER_2D ||
598 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000599 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000600 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000601
602 if (arraySize == 1 && count > 1)
603 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
604
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000605 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000606
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000607 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
608 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000609 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000610 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000611 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000612 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000613
614 if (arraySize == 1 && count > 1)
615 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
616
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000617 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000618 GLboolean *boolParams = new GLboolean[count];
619
620 for (int i = 0; i < count; ++i)
621 {
622 if (v[i] == 0)
623 {
624 boolParams[i] = GL_FALSE;
625 }
626 else
627 {
628 boolParams[i] = GL_TRUE;
629 }
630 }
631
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000632 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
633 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000634
635 delete [] boolParams;
636 }
637 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000638 {
639 return false;
640 }
641
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000642 return true;
643}
644
645bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
646{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000647 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000648 {
649 return false;
650 }
651
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000652 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000653 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000654
655 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000656 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000657 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000658
659 if (arraySize == 1 && count > 1)
660 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
661
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000662 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000663
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000664 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
665 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000666 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000667 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000668 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000669 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000670
671 if (arraySize == 1 && count > 1)
672 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
673
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000674 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000675 GLboolean *boolParams = new GLboolean[count * 2];
676
677 for (int i = 0; i < count * 2; ++i)
678 {
679 if (v[i] == 0)
680 {
681 boolParams[i] = GL_FALSE;
682 }
683 else
684 {
685 boolParams[i] = GL_TRUE;
686 }
687 }
688
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000689 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
690 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000691
692 delete [] boolParams;
693 }
694 else
695 {
696 return false;
697 }
698
699 return true;
700}
701
702bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
703{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000704 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000705 {
706 return false;
707 }
708
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000709 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000710 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000711
712 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000713 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000714 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000715
716 if (arraySize == 1 && count > 1)
717 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
718
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000719 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000720
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000721 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
722 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000723 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000724 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000725 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000726 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000727
728 if (arraySize == 1 && count > 1)
729 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
730
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000731 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000732 GLboolean *boolParams = new GLboolean[count * 3];
733
734 for (int i = 0; i < count * 3; ++i)
735 {
736 if (v[i] == 0)
737 {
738 boolParams[i] = GL_FALSE;
739 }
740 else
741 {
742 boolParams[i] = GL_TRUE;
743 }
744 }
745
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000746 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
747 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000748
749 delete [] boolParams;
750 }
751 else
752 {
753 return false;
754 }
755
756 return true;
757}
758
759bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
760{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000761 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000762 {
763 return false;
764 }
765
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000766 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000767 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000768
769 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000770 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000771 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000772
773 if (arraySize == 1 && count > 1)
774 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
775
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000776 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000777
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000778 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
779 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000780 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000781 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000782 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000783 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000784
785 if (arraySize == 1 && count > 1)
786 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
787
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000788 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000789 GLboolean *boolParams = new GLboolean[count * 4];
790
791 for (int i = 0; i < count * 4; ++i)
792 {
793 if (v[i] == 0)
794 {
795 boolParams[i] = GL_FALSE;
796 }
797 else
798 {
799 boolParams[i] = GL_TRUE;
800 }
801 }
802
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000803 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
804 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000805
806 delete [] boolParams;
807 }
808 else
809 {
810 return false;
811 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000812
813 return true;
814}
815
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000816bool Program::getUniformfv(GLint location, GLfloat *params)
817{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000818 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000819 {
820 return false;
821 }
822
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000823 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000824
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000825 unsigned int count = UniformComponentCount(targetUniform->type);
826
827 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000828 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000829 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000830 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000831 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000832
833 for (unsigned int i = 0; i < count; ++i)
834 {
835 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
836 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000837 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000838 break;
839 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000840 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
841 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000842 break;
843 case GL_INT:
844 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000845 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000846
847 for (unsigned int i = 0; i < count; ++i)
848 {
849 params[i] = (float)intParams[i];
850 }
851 }
852 break;
853 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000854 }
855
856 return true;
857}
858
859bool Program::getUniformiv(GLint location, GLint *params)
860{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000861 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000862 {
863 return false;
864 }
865
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000866 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000867
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000868 unsigned int count = UniformComponentCount(targetUniform->type);
869
870 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000871 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000872 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000873 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000874 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000875
876 for (unsigned int i = 0; i < count; ++i)
877 {
878 params[i] = (GLint)boolParams[i];
879 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000880 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000881 break;
882 case GL_FLOAT:
883 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000884 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000885
886 for (unsigned int i = 0; i < count; ++i)
887 {
888 params[i] = (GLint)floatParams[i];
889 }
890 }
891 break;
892 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000893 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
894 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000895 break;
896 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000897 }
898
899 return true;
900}
901
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000902void Program::dirtyAllUniforms()
903{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000904 unsigned int numUniforms = mUniforms.size();
905 for (unsigned int index = 0; index < numUniforms; index++)
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000906 {
907 mUniforms[index]->dirty = true;
908 }
909}
910
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000911void Program::dirtyAllSamplers()
912{
913 for (unsigned int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; ++index)
914 {
915 mSamplers[index].dirty = true;
916 }
917}
918
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000919// Applies all the uniforms set for this program object to the Direct3D 9 device
920void Program::applyUniforms()
921{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000922 unsigned int numUniforms = mUniformIndex.size();
923 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000924 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000925 if (mUniformIndex[location].element != 0)
926 {
927 continue;
928 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000929
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000930 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
931
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000932 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000933 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000934 int arraySize = targetUniform->arraySize;
935 GLfloat *f = (GLfloat*)targetUniform->data;
936 GLint *i = (GLint*)targetUniform->data;
937 GLboolean *b = (GLboolean*)targetUniform->data;
938
939 switch (targetUniform->type)
940 {
941 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
942 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
943 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
944 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
945 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
946 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
947 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
948 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
949 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
950 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
951 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000952 case GL_SAMPLER_2D:
953 case GL_SAMPLER_CUBE:
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000954 case GL_INT: applyUniform1iv(location, arraySize, i); break;
955 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
956 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
957 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
958 default:
959 UNREACHABLE();
960 }
961
962 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000963 }
964 }
965}
966
967// Compiles the HLSL code of the attached shaders into executable binaries
968ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
969{
970 if (!hlsl)
971 {
972 return NULL;
973 }
974
975 ID3DXBuffer *binary = NULL;
976 ID3DXBuffer *errorMessage = NULL;
977
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000978 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, NULL, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000979
980 if (SUCCEEDED(result))
981 {
982 return binary;
983 }
984
985 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
986 {
987 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
988 }
989
990 if (errorMessage)
991 {
992 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000993
daniel@transgaming.com0df16872010-05-12 16:51:08 +0000994 appendToInfoLog("%s\n", message);
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000995 TRACE("\n%s", hlsl);
996 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000997 }
998
999 return NULL;
1000}
1001
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001002// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1003// Returns the number of used varying registers, or -1 if unsuccesful
1004int Program::packVaryings(const Varying *packing[][4])
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001005{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001006 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001007 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001008 int n = VariableRowCount(varying->type) * varying->size;
1009 int m = VariableColumnCount(varying->type);
1010 bool success = false;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001011
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001012 if (m == 2 || m == 3 || m == 4)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001013 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001014 for (int r = 0; r <= MAX_VARYING_VECTORS - n && !success; r++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001015 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001016 bool available = true;
1017
1018 for (int y = 0; y < n && available; y++)
1019 {
1020 for (int x = 0; x < m && available; x++)
1021 {
1022 if (packing[r + y][x])
1023 {
1024 available = false;
1025 }
1026 }
1027 }
1028
1029 if (available)
1030 {
1031 varying->reg = r;
1032 varying->col = 0;
1033
1034 for (int y = 0; y < n; y++)
1035 {
1036 for (int x = 0; x < m; x++)
1037 {
1038 packing[r + y][x] = &*varying;
1039 }
1040 }
1041
1042 success = true;
1043 }
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001044 }
1045
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001046 if (!success && m == 2)
1047 {
1048 for (int r = MAX_VARYING_VECTORS - n; r >= 0 && !success; r--)
1049 {
1050 bool available = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001051
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001052 for (int y = 0; y < n && available; y++)
1053 {
1054 for (int x = 2; x < 4 && available; x++)
1055 {
1056 if (packing[r + y][x])
1057 {
1058 available = false;
1059 }
1060 }
1061 }
1062
1063 if (available)
1064 {
1065 varying->reg = r;
1066 varying->col = 2;
1067
1068 for (int y = 0; y < n; y++)
1069 {
1070 for (int x = 2; x < 4; x++)
1071 {
1072 packing[r + y][x] = &*varying;
1073 }
1074 }
1075
1076 success = true;
1077 }
1078 }
1079 }
1080 }
1081 else if (m == 1)
1082 {
1083 int space[4] = {0};
1084
1085 for (int y = 0; y < MAX_VARYING_VECTORS; y++)
1086 {
1087 for (int x = 0; x < 4; x++)
1088 {
1089 space[x] += packing[y][x] ? 0 : 1;
1090 }
1091 }
1092
1093 int column = 0;
1094
1095 for (int x = 0; x < 4; x++)
1096 {
1097 if (space[x] > n && space[x] < space[column])
1098 {
1099 column = x;
1100 }
1101 }
1102
1103 if (space[column] > n)
1104 {
1105 for (int r = 0; r < MAX_VARYING_VECTORS; r++)
1106 {
1107 if (!packing[r][column])
1108 {
1109 varying->reg = r;
1110
1111 for (int y = r; y < r + n; y++)
1112 {
1113 packing[y][column] = &*varying;
1114 }
1115
1116 break;
1117 }
1118 }
1119
1120 varying->col = column;
1121
1122 success = true;
1123 }
1124 }
1125 else UNREACHABLE();
1126
1127 if (!success)
1128 {
1129 appendToInfoLog("Could not pack varying %s", varying->name.c_str());
1130
1131 return -1;
1132 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001133 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001134
1135 // Return the number of used registers
1136 int registers = 0;
1137
1138 for (int r = 0; r < MAX_VARYING_VECTORS; r++)
1139 {
1140 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1141 {
1142 registers++;
1143 }
1144 }
1145
1146 return registers;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001147}
1148
1149bool Program::linkVaryings()
1150{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001151 if (mPixelHLSL.empty() || mVertexHLSL.empty())
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001152 {
1153 return false;
1154 }
1155
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001156 const Varying *packing[MAX_VARYING_VECTORS][4] = {NULL};
1157 int registers = packVaryings(packing);
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001158
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001159 if (registers < 0)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001160 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001161 return false;
1162 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001163
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001164 if (registers == MAX_VARYING_VECTORS && mFragmentShader->mUsesFragCoord)
1165 {
1166 appendToInfoLog("No varying registers left to support gl_FragCoord");
1167
1168 return false;
1169 }
1170
1171 for (VaryingList::iterator input = mFragmentShader->varyings.begin(); input != mFragmentShader->varyings.end(); input++)
1172 {
1173 bool matched = false;
1174
1175 for (VaryingList::iterator output = mVertexShader->varyings.begin(); output != mVertexShader->varyings.end(); output++)
1176 {
1177 if (output->name == input->name)
1178 {
1179 if (output->type != input->type || output->size != input->size)
1180 {
1181 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
1182
1183 return false;
1184 }
1185
1186 output->reg = input->reg;
1187 output->col = input->col;
1188
1189 matched = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001190 break;
1191 }
1192 }
1193
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001194 if (!matched)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001195 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001196 appendToInfoLog("Fragment varying varying %s does not match any vertex varying", input->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001197
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001198 return false;
1199 }
1200 }
1201
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001202 Context *context = getContext();
1203 bool sm3 = context->supportsShaderModel3();
1204 std::string varyingSemantic = (sm3 ? "COLOR" : "TEXCOORD");
1205
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001206 mVertexHLSL += "struct VS_INPUT\n"
1207 "{\n";
1208
1209 int semanticIndex = 0;
1210 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1211 {
1212 switch (attribute->type)
1213 {
1214 case GL_FLOAT: mVertexHLSL += " float "; break;
1215 case GL_FLOAT_VEC2: mVertexHLSL += " float2 "; break;
1216 case GL_FLOAT_VEC3: mVertexHLSL += " float3 "; break;
1217 case GL_FLOAT_VEC4: mVertexHLSL += " float4 "; break;
1218 case GL_FLOAT_MAT2: mVertexHLSL += " float2x2 "; break;
1219 case GL_FLOAT_MAT3: mVertexHLSL += " float3x3 "; break;
1220 case GL_FLOAT_MAT4: mVertexHLSL += " float4x4 "; break;
1221 default: UNREACHABLE();
1222 }
1223
1224 mVertexHLSL += decorate(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1225
1226 semanticIndex += VariableRowCount(attribute->type);
1227 }
1228
1229 mVertexHLSL += "};\n"
1230 "\n"
1231 "struct VS_OUTPUT\n"
1232 "{\n"
1233 " float4 gl_Position : POSITION;\n";
1234
1235 for (int r = 0; r < registers; r++)
1236 {
1237 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1238
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001239 mVertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001240 }
1241
1242 if (mFragmentShader->mUsesFragCoord)
1243 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001244 mVertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1245 }
1246
1247 if (mVertexShader->mUsesPointSize && sm3)
1248 {
1249 mVertexHLSL += " float gl_PointSize : PSIZE;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001250 }
1251
1252 mVertexHLSL += "};\n"
1253 "\n"
1254 "VS_OUTPUT main(VS_INPUT input)\n"
1255 "{\n";
1256
1257 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1258 {
1259 mVertexHLSL += " " + decorate(attribute->name) + " = ";
1260
1261 if (VariableRowCount(attribute->type) > 1) // Matrix
1262 {
1263 mVertexHLSL += "transpose";
1264 }
1265
1266 mVertexHLSL += "(input." + decorate(attribute->name) + ");\n";
1267 }
1268
1269 mVertexHLSL += "\n"
1270 " gl_main();\n"
1271 "\n"
1272 " VS_OUTPUT output;\n"
1273 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
1274 " output.gl_Position.y = -(gl_Position.y - dx_HalfPixelSize.y * gl_Position.w);\n"
1275 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1276 " output.gl_Position.w = gl_Position.w;\n";
1277
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001278 if (mVertexShader->mUsesPointSize && sm3)
1279 {
1280 mVertexHLSL += " output.gl_PointSize = clamp(gl_PointSize, 1.0, " + str((int)ALIASED_POINT_SIZE_RANGE_MAX_SM3) + ");\n";
1281 }
1282
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001283 if (mFragmentShader->mUsesFragCoord)
1284 {
1285 mVertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1286 }
1287
1288 for (VaryingList::iterator varying = mVertexShader->varyings.begin(); varying != mVertexShader->varyings.end(); varying++)
1289 {
1290 if (varying->reg >= 0)
1291 {
1292 for (int i = 0; i < varying->size; i++)
1293 {
1294 int rows = VariableRowCount(varying->type);
1295
1296 for (int j = 0; j < rows; j++)
1297 {
1298 int r = varying->reg + i * rows + j;
1299 mVertexHLSL += " output.v" + str(r);
1300
1301 bool sharedRegister = false; // Register used by multiple varyings
1302
1303 for (int x = 0; x < 4; x++)
1304 {
1305 if (packing[r][x] && packing[r][x] != packing[r][0])
1306 {
1307 sharedRegister = true;
1308 break;
1309 }
1310 }
1311
1312 if(sharedRegister)
1313 {
1314 mVertexHLSL += ".";
1315
1316 for (int x = 0; x < 4; x++)
1317 {
1318 if (packing[r][x] == &*varying)
1319 {
1320 switch(x)
1321 {
1322 case 0: mVertexHLSL += "x"; break;
1323 case 1: mVertexHLSL += "y"; break;
1324 case 2: mVertexHLSL += "z"; break;
1325 case 3: mVertexHLSL += "w"; break;
1326 }
1327 }
1328 }
1329 }
1330
1331 mVertexHLSL += " = " + varying->name;
1332
1333 if (varying->array)
1334 {
1335 mVertexHLSL += "[" + str(i) + "]";
1336 }
1337
1338 if (rows > 1)
1339 {
1340 mVertexHLSL += "[" + str(j) + "]";
1341 }
1342
1343 mVertexHLSL += ";\n";
1344 }
1345 }
1346 }
1347 }
1348
1349 mVertexHLSL += "\n"
1350 " return output;\n"
1351 "}\n";
1352
1353 mPixelHLSL += "struct PS_INPUT\n"
1354 "{\n";
1355
1356 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1357 {
1358 if (varying->reg >= 0)
1359 {
1360 for (int i = 0; i < varying->size; i++)
1361 {
1362 int rows = VariableRowCount(varying->type);
1363 for (int j = 0; j < rows; j++)
1364 {
1365 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001366 mPixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001367 }
1368 }
1369 }
1370 else UNREACHABLE();
1371 }
1372
1373 if (mFragmentShader->mUsesFragCoord)
1374 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001375 mPixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001376 if (sm3) {
1377 mPixelHLSL += " float4 dx_VPos : VPOS;\n";
1378 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001379 }
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001380
1381 if (mFragmentShader->mUsesPointCoord && sm3)
1382 {
1383 mPixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1384 }
1385
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001386 if (mFragmentShader->mUsesFrontFacing)
1387 {
1388 mPixelHLSL += " float vFace : VFACE;\n";
1389 }
1390
1391 mPixelHLSL += "};\n"
1392 "\n"
1393 "struct PS_OUTPUT\n"
1394 "{\n"
1395 " float4 gl_Color[1] : COLOR;\n"
1396 "};\n"
1397 "\n"
1398 "PS_OUTPUT main(PS_INPUT input)\n"
1399 "{\n";
1400
1401 if (mFragmentShader->mUsesFragCoord)
1402 {
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001403 mPixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1404 if (sm3) {
1405 mPixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1406 " gl_FragCoord.y = input.dx_VPos.y;\n";
1407 } else {
1408 mPixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Viewport.x + dx_Viewport.z;\n"
1409 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Viewport.y + dx_Viewport.w;\n";
1410 }
1411 mPixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001412 " gl_FragCoord.w = rhw;\n";
1413 }
1414
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001415 if (mFragmentShader->mUsesPointCoord && sm3)
1416 {
1417 mPixelHLSL += " gl_PointCoord = float2(input.gl_PointCoord.x, 1.0 - input.gl_PointCoord.y);\n";
1418 }
1419
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001420 if (mFragmentShader->mUsesFrontFacing)
1421 {
1422 mPixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1423 }
1424
1425 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1426 {
1427 if (varying->reg >= 0)
1428 {
1429 for (int i = 0; i < varying->size; i++)
1430 {
1431 int rows = VariableRowCount(varying->type);
1432 for (int j = 0; j < rows; j++)
1433 {
1434 std::string n = str(varying->reg + i * rows + j);
1435 mPixelHLSL += " " + varying->name;
1436
1437 if (varying->array)
1438 {
1439 mPixelHLSL += "[" + str(i) + "]";
1440 }
1441
1442 if (rows > 1)
1443 {
1444 mPixelHLSL += "[" + str(j) + "]";
1445 }
1446
1447 mPixelHLSL += " = input.v" + n + ";\n";
1448 }
1449 }
1450 }
1451 else UNREACHABLE();
1452 }
1453
1454 mPixelHLSL += "\n"
1455 " gl_main();\n"
1456 "\n"
1457 " PS_OUTPUT output;\n"
1458 " output.gl_Color[0] = gl_Color[0];\n"
1459 "\n"
1460 " return output;\n"
1461 "}\n";
1462
1463 TRACE("\n%s", mPixelHLSL.c_str());
1464 TRACE("\n%s", mVertexHLSL.c_str());
1465
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001466 return true;
1467}
1468
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001469// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1470// compiling them into binaries, determining the attribute mappings, and collecting
1471// a list of uniforms
1472void Program::link()
1473{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001474 unlink();
1475
1476 if (!mFragmentShader || !mFragmentShader->isCompiled())
1477 {
1478 return;
1479 }
1480
1481 if (!mVertexShader || !mVertexShader->isCompiled())
1482 {
1483 return;
1484 }
1485
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001486 mPixelHLSL = mFragmentShader->getHLSL();
1487 mVertexHLSL = mVertexShader->getHLSL();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001488
1489 if (!linkVaryings())
1490 {
1491 return;
1492 }
1493
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001494 Context *context = getContext();
1495 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1496 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1497
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001498 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1499 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001500
1501 if (vertexBinary && pixelBinary)
1502 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001503 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001504 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1505 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1506
1507 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1508 {
1509 return error(GL_OUT_OF_MEMORY);
1510 }
1511
1512 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001513
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001514 vertexBinary->Release();
1515 pixelBinary->Release();
1516 vertexBinary = NULL;
1517 pixelBinary = NULL;
1518
1519 if (mVertexExecutable && mPixelExecutable)
1520 {
1521 if (!linkAttributes())
1522 {
1523 return;
1524 }
1525
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001526 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001527 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001528 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001529 }
1530
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001531 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001532 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001533 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001534 }
1535
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001536 // these uniforms are searched as already-decorated because gl_ and dx_
1537 // are reserved prefixes, and do not receive additional decoration
1538 mDepthRangeNearLocation = getUniformLocation("gl_DepthRange.near", true);
1539 mDepthRangeFarLocation = getUniformLocation("gl_DepthRange.far", true);
1540 mDepthRangeDiffLocation = getUniformLocation("gl_DepthRange.diff", true);
1541 mDxDepthLocation = getUniformLocation("dx_Depth", true);
daniel@transgaming.com162267d2010-07-28 19:20:48 +00001542 mDxViewportLocation = getUniformLocation("dx_Viewport", true);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001543 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize", true);
1544 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW", true);
1545 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines", true);
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00001546
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001547 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001548 }
1549 }
1550}
1551
1552// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1553bool Program::linkAttributes()
1554{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001555 unsigned int usedLocations = 0;
1556
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001557 // Link attributes that have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001558 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001559 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001560 int location = getAttributeBinding(attribute->name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001561
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001562 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001563 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001564 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001565 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001566 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001567 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001568
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001569 mLinkedAttribute[location] = *attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001570
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001571 int rows = VariableRowCount(attribute->type);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001572
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001573 if (rows + location > MAX_VERTEX_ATTRIBS)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001574 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001575 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 +00001576
1577 return false;
1578 }
1579
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001580 for (int i = 0; i < rows; i++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001581 {
1582 usedLocations |= 1 << (location + i);
1583 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001584 }
1585 }
1586
1587 // Link attributes that don't have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001588 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001589 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001590 int location = getAttributeBinding(attribute->name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001591
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001592 if (location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001593 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001594 int rows = VariableRowCount(attribute->type);
1595 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001596
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001597 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001598 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001599 appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001600
1601 return false; // Fail to link
1602 }
1603
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001604 mLinkedAttribute[availableIndex] = *attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001605 }
1606 }
1607
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001608 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001609 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001610 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001611 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001612
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001613 for (int r = 0; r < rows; r++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001614 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001615 mSemanticIndex[attributeIndex++] = index++;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001616 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001617 }
1618
1619 return true;
1620}
1621
daniel@transgaming.com85423182010-04-22 13:35:27 +00001622int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001623{
1624 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1625 {
1626 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1627 {
1628 return location;
1629 }
1630 }
1631
1632 return -1;
1633}
1634
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001635bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1636{
1637 D3DXCONSTANTTABLE_DESC constantTableDescription;
1638 D3DXCONSTANT_DESC constantDescription;
1639 UINT descriptionCount = 1;
1640
1641 constantTable->GetDesc(&constantTableDescription);
1642
1643 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1644 {
1645 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1646 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1647
1648 if (!defineUniform(constantHandle, constantDescription))
1649 {
1650 return false;
1651 }
1652 }
1653
1654 return true;
1655}
1656
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001657// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001658// Returns true if succesful (uniform not already defined)
1659bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1660{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001661 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1662 {
1663 unsigned int samplerIndex = constantDescription.RegisterIndex;
1664
1665 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1666
1667 mSamplers[samplerIndex].active = true;
1668 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1669 mSamplers[samplerIndex].logicalTextureUnit = 0;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001670 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001671 }
1672
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001673 switch(constantDescription.Class)
1674 {
1675 case D3DXPC_STRUCT:
1676 {
1677 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1678 {
1679 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1680
1681 D3DXCONSTANT_DESC fieldDescription;
1682 UINT descriptionCount = 1;
1683
1684 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1685
1686 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1687 {
1688 return false;
1689 }
1690 }
1691
1692 return true;
1693 }
1694 case D3DXPC_SCALAR:
1695 case D3DXPC_VECTOR:
1696 case D3DXPC_MATRIX_COLUMNS:
1697 case D3DXPC_OBJECT:
1698 return defineUniform(constantDescription, name + constantDescription.Name);
1699 default:
1700 UNREACHABLE();
1701 return false;
1702 }
1703}
1704
1705bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1706{
1707 Uniform *uniform = createUniform(constantDescription, name);
1708
1709 if(!uniform)
1710 {
1711 return false;
1712 }
1713
1714 // Check if already defined
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001715 GLint location = getUniformLocation(name.c_str(), true);
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001716 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001717
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001718 if (location >= 0)
1719 {
1720 delete uniform;
1721
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001722 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001723 {
1724 return false;
1725 }
1726 else
1727 {
1728 return true;
1729 }
1730 }
1731
1732 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001733 unsigned int uniformIndex = mUniforms.size() - 1;
1734
1735 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1736 {
1737 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1738 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001739
1740 return true;
1741}
1742
1743Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001744{
1745 if (constantDescription.Rows == 1) // Vectors and scalars
1746 {
1747 switch (constantDescription.Type)
1748 {
1749 case D3DXPT_SAMPLER2D:
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001750 switch (constantDescription.Columns)
1751 {
1752 case 1: return new Uniform(GL_SAMPLER_2D, name, constantDescription.Elements);
1753 default: UNREACHABLE();
1754 }
1755 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001756 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001757 switch (constantDescription.Columns)
1758 {
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001759 case 1: return new Uniform(GL_SAMPLER_CUBE, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001760 default: UNREACHABLE();
1761 }
1762 break;
1763 case D3DXPT_BOOL:
1764 switch (constantDescription.Columns)
1765 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001766 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1767 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1768 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1769 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001770 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001771 }
1772 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001773 case D3DXPT_INT:
1774 switch (constantDescription.Columns)
1775 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001776 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1777 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1778 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1779 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001780 default: UNREACHABLE();
1781 }
1782 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001783 case D3DXPT_FLOAT:
1784 switch (constantDescription.Columns)
1785 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001786 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1787 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1788 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1789 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001790 default: UNREACHABLE();
1791 }
1792 break;
1793 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001794 UNREACHABLE();
1795 }
1796 }
1797 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1798 {
1799 switch (constantDescription.Type)
1800 {
1801 case D3DXPT_FLOAT:
1802 switch (constantDescription.Rows)
1803 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001804 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1805 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1806 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001807 default: UNREACHABLE();
1808 }
1809 break;
1810 default: UNREACHABLE();
1811 }
1812 }
1813 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001814
1815 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001816}
1817
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001818// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001819std::string Program::decorate(const std::string &string)
1820{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001821 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001822 {
1823 return "_" + string;
1824 }
1825 else
1826 {
1827 return string;
1828 }
1829}
1830
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001831std::string Program::undecorate(const std::string &string)
1832{
1833 if (string.substr(0, 1) == "_")
1834 {
1835 return string.substr(1);
1836 }
1837 else
1838 {
1839 return string;
1840 }
1841}
1842
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001843bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1844{
1845 BOOL *vector = new BOOL[count];
1846 for (int i = 0; i < count; i++)
1847 {
1848 if (v[i] == GL_FALSE)
1849 vector[i] = 0;
1850 else
1851 vector[i] = 1;
1852 }
1853
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001854 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1855
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001856 D3DXHANDLE constantPS;
1857 D3DXHANDLE constantVS;
1858 getConstantHandles(targetUniform, &constantPS, &constantVS);
1859
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001860 IDirect3DDevice9 *device = getDevice();
1861
1862 if (constantPS)
1863 {
1864 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1865 }
1866
1867 if (constantVS)
1868 {
1869 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1870 }
1871
1872 delete [] vector;
1873
1874 return true;
1875}
1876
1877bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1878{
1879 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1880
1881 for (int i = 0; i < count; i++)
1882 {
1883 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1884 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1885
1886 v += 2;
1887 }
1888
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001889 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1890
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001891 D3DXHANDLE constantPS;
1892 D3DXHANDLE constantVS;
1893 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001894 IDirect3DDevice9 *device = getDevice();
1895
1896 if (constantPS)
1897 {
1898 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1899 }
1900
1901 if (constantVS)
1902 {
1903 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1904 }
1905
1906 delete[] vector;
1907
1908 return true;
1909}
1910
1911bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1912{
1913 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1914
1915 for (int i = 0; i < count; i++)
1916 {
1917 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1918 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1919 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1920
1921 v += 3;
1922 }
1923
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001924 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1925
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001926 D3DXHANDLE constantPS;
1927 D3DXHANDLE constantVS;
1928 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001929 IDirect3DDevice9 *device = getDevice();
1930
1931 if (constantPS)
1932 {
1933 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1934 }
1935
1936 if (constantVS)
1937 {
1938 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1939 }
1940
1941 delete[] vector;
1942
1943 return true;
1944}
1945
1946bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1947{
1948 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1949
1950 for (int i = 0; i < count; i++)
1951 {
1952 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1953 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1954 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1955 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1956
1957 v += 3;
1958 }
1959
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001960 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1961
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001962 D3DXHANDLE constantPS;
1963 D3DXHANDLE constantVS;
1964 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001965 IDirect3DDevice9 *device = getDevice();
1966
1967 if (constantPS)
1968 {
1969 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1970 }
1971
1972 if (constantVS)
1973 {
1974 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1975 }
1976
1977 delete [] vector;
1978
1979 return true;
1980}
1981
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001982bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1983{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001984 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1985
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001986 D3DXHANDLE constantPS;
1987 D3DXHANDLE constantVS;
1988 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001989 IDirect3DDevice9 *device = getDevice();
1990
1991 if (constantPS)
1992 {
1993 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1994 }
1995
1996 if (constantVS)
1997 {
1998 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1999 }
2000
2001 return true;
2002}
2003
2004bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
2005{
2006 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2007
2008 for (int i = 0; i < count; i++)
2009 {
2010 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
2011
2012 v += 2;
2013 }
2014
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002015 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2016
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002017 D3DXHANDLE constantPS;
2018 D3DXHANDLE constantVS;
2019 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002020 IDirect3DDevice9 *device = getDevice();
2021
2022 if (constantPS)
2023 {
2024 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2025 }
2026
2027 if (constantVS)
2028 {
2029 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2030 }
2031
2032 delete[] vector;
2033
2034 return true;
2035}
2036
2037bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
2038{
2039 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2040
2041 for (int i = 0; i < count; i++)
2042 {
2043 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
2044
2045 v += 3;
2046 }
2047
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002048 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2049
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002050 D3DXHANDLE constantPS;
2051 D3DXHANDLE constantVS;
2052 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002053 IDirect3DDevice9 *device = getDevice();
2054
2055 if (constantPS)
2056 {
2057 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2058 }
2059
2060 if (constantVS)
2061 {
2062 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2063 }
2064
2065 delete[] vector;
2066
2067 return true;
2068}
2069
2070bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
2071{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002072 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2073
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002074 D3DXHANDLE constantPS;
2075 D3DXHANDLE constantVS;
2076 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002077 IDirect3DDevice9 *device = getDevice();
2078
2079 if (constantPS)
2080 {
2081 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
2082 }
2083
2084 if (constantVS)
2085 {
2086 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
2087 }
2088
2089 return true;
2090}
2091
2092bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
2093{
2094 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2095
2096 for (int i = 0; i < count; i++)
2097 {
2098 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
2099 value[1], value[3], 0, 0,
2100 0, 0, 1, 0,
2101 0, 0, 0, 1);
2102
2103 value += 4;
2104 }
2105
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002106 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2107
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002108 D3DXHANDLE constantPS;
2109 D3DXHANDLE constantVS;
2110 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002111 IDirect3DDevice9 *device = getDevice();
2112
2113 if (constantPS)
2114 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002115 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002116 }
2117
2118 if (constantVS)
2119 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002120 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002121 }
2122
2123 delete[] matrix;
2124
2125 return true;
2126}
2127
2128bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
2129{
2130 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2131
2132 for (int i = 0; i < count; i++)
2133 {
2134 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
2135 value[1], value[4], value[7], 0,
2136 value[2], value[5], value[8], 0,
2137 0, 0, 0, 1);
2138
2139 value += 9;
2140 }
2141
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002142 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2143
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002144 D3DXHANDLE constantPS;
2145 D3DXHANDLE constantVS;
2146 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002147 IDirect3DDevice9 *device = getDevice();
2148
2149 if (constantPS)
2150 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002151 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002152 }
2153
2154 if (constantVS)
2155 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002156 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002157 }
2158
2159 delete[] matrix;
2160
2161 return true;
2162}
2163
2164bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
2165{
2166 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2167
2168 for (int i = 0; i < count; i++)
2169 {
2170 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
2171 value[1], value[5], value[9], value[13],
2172 value[2], value[6], value[10], value[14],
2173 value[3], value[7], value[11], value[15]);
2174
2175 value += 16;
2176 }
2177
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002178 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2179
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002180 D3DXHANDLE constantPS;
2181 D3DXHANDLE constantVS;
2182 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002183 IDirect3DDevice9 *device = getDevice();
2184
2185 if (constantPS)
2186 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002187 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002188 }
2189
2190 if (constantVS)
2191 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002192 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002193 }
2194
2195 delete[] matrix;
2196
2197 return true;
2198}
2199
2200bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
2201{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002202 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2203
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002204 D3DXHANDLE constantPS;
2205 D3DXHANDLE constantVS;
2206 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002207 IDirect3DDevice9 *device = getDevice();
2208
2209 if (constantPS)
2210 {
2211 D3DXCONSTANT_DESC constantDescription;
2212 UINT descriptionCount = 1;
2213 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
2214
daniel@transgaming.com2884b782010-03-08 21:30:48 +00002215 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002216 {
2217 return false;
2218 }
2219
2220 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2221 {
2222 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
2223
2224 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
2225 {
2226 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002227
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002228 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002229 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002230 ASSERT(mSamplers[samplerIndex].active);
2231 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
2232 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002233 }
2234 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002235
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002236 return true;
2237 }
2238 }
2239
2240 if (constantPS)
2241 {
2242 mConstantTablePS->SetIntArray(device, constantPS, v, count);
2243 }
2244
2245 if (constantVS)
2246 {
2247 mConstantTableVS->SetIntArray(device, constantVS, v, count);
2248 }
2249
2250 return true;
2251}
2252
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002253bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
2254{
2255 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2256
2257 for (int i = 0; i < count; i++)
2258 {
2259 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2260
2261 v += 2;
2262 }
2263
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002264 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2265
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002266 D3DXHANDLE constantPS;
2267 D3DXHANDLE constantVS;
2268 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002269 IDirect3DDevice9 *device = getDevice();
2270
2271 if (constantPS)
2272 {
2273 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2274 }
2275
2276 if (constantVS)
2277 {
2278 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2279 }
2280
2281 delete[] vector;
2282
2283 return true;
2284}
2285
2286bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
2287{
2288 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2289
2290 for (int i = 0; i < count; i++)
2291 {
2292 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2293
2294 v += 3;
2295 }
2296
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002297 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2298
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002299 D3DXHANDLE constantPS;
2300 D3DXHANDLE constantVS;
2301 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002302 IDirect3DDevice9 *device = getDevice();
2303
2304 if (constantPS)
2305 {
2306 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2307 }
2308
2309 if (constantVS)
2310 {
2311 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2312 }
2313
2314 delete[] vector;
2315
2316 return true;
2317}
2318
2319bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
2320{
2321 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2322
2323 for (int i = 0; i < count; i++)
2324 {
2325 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2326
2327 v += 4;
2328 }
2329
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002330 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2331
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002332 D3DXHANDLE constantPS;
2333 D3DXHANDLE constantVS;
2334 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002335 IDirect3DDevice9 *device = getDevice();
2336
2337 if (constantPS)
2338 {
2339 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2340 }
2341
2342 if (constantVS)
2343 {
2344 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2345 }
2346
2347 delete [] vector;
2348
2349 return true;
2350}
2351
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002352void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002353{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002354 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002355 {
2356 return;
2357 }
2358
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002359 char info[1024];
2360
2361 va_list vararg;
2362 va_start(vararg, format);
2363 vsnprintf(info, sizeof(info), format, vararg);
2364 va_end(vararg);
2365
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002366 size_t infoLength = strlen(info);
2367
2368 if (!mInfoLog)
2369 {
2370 mInfoLog = new char[infoLength + 1];
2371 strcpy(mInfoLog, info);
2372 }
2373 else
2374 {
2375 size_t logLength = strlen(mInfoLog);
2376 char *newLog = new char[logLength + infoLength + 1];
2377 strcpy(newLog, mInfoLog);
2378 strcpy(newLog + logLength, info);
2379
2380 delete[] mInfoLog;
2381 mInfoLog = newLog;
2382 }
2383}
2384
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002385void Program::resetInfoLog()
2386{
2387 if (mInfoLog)
2388 {
2389 delete [] mInfoLog;
daniel@transgaming.com6a20d102010-08-31 13:54:27 +00002390 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002391 }
2392}
2393
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002394// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
2395void Program::unlink(bool destroy)
2396{
2397 if (destroy) // Object being destructed
2398 {
2399 if (mFragmentShader)
2400 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002401 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002402 mFragmentShader = NULL;
2403 }
2404
2405 if (mVertexShader)
2406 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002407 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002408 mVertexShader = NULL;
2409 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002410 }
2411
2412 if (mPixelExecutable)
2413 {
2414 mPixelExecutable->Release();
2415 mPixelExecutable = NULL;
2416 }
2417
2418 if (mVertexExecutable)
2419 {
2420 mVertexExecutable->Release();
2421 mVertexExecutable = NULL;
2422 }
2423
2424 if (mConstantTablePS)
2425 {
2426 mConstantTablePS->Release();
2427 mConstantTablePS = NULL;
2428 }
2429
2430 if (mConstantTableVS)
2431 {
2432 mConstantTableVS->Release();
2433 mConstantTableVS = NULL;
2434 }
2435
2436 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2437 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002438 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002439 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002440 }
2441
2442 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2443 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00002444 mSamplers[index].active = false;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00002445 mSamplers[index].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002446 }
2447
2448 while (!mUniforms.empty())
2449 {
2450 delete mUniforms.back();
2451 mUniforms.pop_back();
2452 }
2453
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002454 mDepthRangeDiffLocation = -1;
2455 mDepthRangeNearLocation = -1;
2456 mDepthRangeFarLocation = -1;
2457 mDxDepthLocation = -1;
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002458 mDxViewportLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002459 mDxHalfPixelSizeLocation = -1;
2460 mDxFrontCCWLocation = -1;
2461 mDxPointsOrLinesLocation = -1;
2462
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002463 mUniformIndex.clear();
2464
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002465 mPixelHLSL.clear();
2466 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002467
2468 delete[] mInfoLog;
2469 mInfoLog = NULL;
2470
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002471 mLinked = false;
2472}
2473
2474bool Program::isLinked()
2475{
2476 return mLinked;
2477}
2478
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002479bool Program::isValidated() const
2480{
2481 return mValidated;
2482}
2483
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002484void Program::release()
2485{
2486 mRefCount--;
2487
2488 if (mRefCount == 0 && mDeleteStatus)
2489 {
2490 mResourceManager->deleteProgram(mHandle);
2491 }
2492}
2493
2494void Program::addRef()
2495{
2496 mRefCount++;
2497}
2498
2499unsigned int Program::getRefCount() const
2500{
2501 return mRefCount;
2502}
2503
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002504unsigned int Program::getSerial() const
2505{
2506 return mSerial;
2507}
2508
2509unsigned int Program::issueSerial()
2510{
2511 return mCurrentSerial++;
2512}
2513
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002514int Program::getInfoLogLength() const
2515{
2516 if (!mInfoLog)
2517 {
2518 return 0;
2519 }
2520 else
2521 {
2522 return strlen(mInfoLog) + 1;
2523 }
2524}
2525
2526void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2527{
2528 int index = 0;
2529
2530 if (mInfoLog)
2531 {
2532 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2533 {
2534 infoLog[index] = mInfoLog[index];
2535 index++;
2536 }
2537 }
2538
2539 if (bufSize)
2540 {
2541 infoLog[index] = '\0';
2542 }
2543
2544 if (length)
2545 {
2546 *length = index;
2547 }
2548}
2549
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002550void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2551{
2552 int total = 0;
2553
2554 if (mVertexShader)
2555 {
2556 if (total < maxCount)
2557 {
2558 shaders[total] = mVertexShader->getHandle();
2559 }
2560
2561 total++;
2562 }
2563
2564 if (mFragmentShader)
2565 {
2566 if (total < maxCount)
2567 {
2568 shaders[total] = mFragmentShader->getHandle();
2569 }
2570
2571 total++;
2572 }
2573
2574 if (count)
2575 {
2576 *count = total;
2577 }
2578}
2579
daniel@transgaming.com85423182010-04-22 13:35:27 +00002580void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2581{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002582 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002583 for (unsigned int i = 0; i < index; i++)
2584 {
2585 do
2586 {
2587 attribute++;
2588
2589 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2590 }
2591 while (mLinkedAttribute[attribute].name.empty());
2592 }
2593
2594 if (bufsize > 0)
2595 {
2596 const char *string = mLinkedAttribute[attribute].name.c_str();
2597
2598 strncpy(name, string, bufsize);
2599 name[bufsize - 1] = '\0';
2600
2601 if (length)
2602 {
2603 *length = strlen(name);
2604 }
2605 }
2606
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002607 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002608
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002609 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002610}
2611
2612GLint Program::getActiveAttributeCount()
2613{
2614 int count = 0;
2615
2616 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2617 {
2618 if (!mLinkedAttribute[attributeIndex].name.empty())
2619 {
2620 count++;
2621 }
2622 }
2623
2624 return count;
2625}
2626
2627GLint Program::getActiveAttributeMaxLength()
2628{
2629 int maxLength = 0;
2630
2631 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2632 {
2633 if (!mLinkedAttribute[attributeIndex].name.empty())
2634 {
2635 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2636 }
2637 }
2638
2639 return maxLength;
2640}
2641
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002642void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2643{
2644 unsigned int uniform = 0;
2645 for (unsigned int i = 0; i < index; i++)
2646 {
2647 do
2648 {
2649 uniform++;
2650
2651 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2652 }
2653 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2654 }
2655
2656 if (bufsize > 0)
2657 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002658 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002659
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002660 if (mUniforms[uniform]->arraySize != 1)
2661 {
2662 string += "[0]";
2663 }
2664
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002665 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002666 name[bufsize - 1] = '\0';
2667
2668 if (length)
2669 {
2670 *length = strlen(name);
2671 }
2672 }
2673
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002674 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002675
2676 *type = mUniforms[uniform]->type;
2677}
2678
2679GLint Program::getActiveUniformCount()
2680{
2681 int count = 0;
2682
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002683 unsigned int numUniforms = mUniforms.size();
2684 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002685 {
2686 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2687 {
2688 count++;
2689 }
2690 }
2691
2692 return count;
2693}
2694
2695GLint Program::getActiveUniformMaxLength()
2696{
2697 int maxLength = 0;
2698
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002699 unsigned int numUniforms = mUniforms.size();
2700 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002701 {
2702 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2703 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002704 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002705 }
2706 }
2707
2708 return maxLength;
2709}
2710
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002711void Program::flagForDeletion()
2712{
2713 mDeleteStatus = true;
2714}
2715
2716bool Program::isFlaggedForDeletion() const
2717{
2718 return mDeleteStatus;
2719}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002720
2721void Program::validate()
2722{
2723 resetInfoLog();
2724
2725 if (!isLinked())
2726 {
2727 appendToInfoLog("Program has not been successfully linked.");
2728 mValidated = false;
2729 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002730 else
2731 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002732 applyUniforms();
2733 if (!validateSamplers())
2734 {
2735 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2736 mValidated = false;
2737 }
2738 else
2739 {
2740 mValidated = true;
2741 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002742 }
2743}
2744
2745bool Program::validateSamplers() const
2746{
2747 // if any two active samplers in a program are of different types, but refer to the same
2748 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2749 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2750 std::map<int, SamplerType> samplerMap;
2751 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2752 {
2753 if (mSamplers[i].active)
2754 {
2755 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2756 {
2757 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2758 return false;
2759 }
2760 else
2761 {
2762 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2763 }
2764 }
2765 }
2766
2767 return true;
2768}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002769
2770void Program::getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS)
2771{
2772 if (!targetUniform->handlesSet)
2773 {
2774 targetUniform->psHandle = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2775 targetUniform->vsHandle = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
2776 targetUniform->handlesSet = true;
2777 }
2778
2779 *constantPS = targetUniform->psHandle;
2780 *constantVS = targetUniform->vsHandle;
2781}
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002782
2783GLint Program::getDepthRangeDiffLocation() const
2784{
2785 return mDepthRangeDiffLocation;
2786}
2787
2788GLint Program::getDepthRangeNearLocation() const
2789{
daniel@transgaming.come0d7d432010-05-18 18:51:52 +00002790 return mDepthRangeNearLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002791}
2792
2793GLint Program::getDepthRangeFarLocation() const
2794{
2795 return mDepthRangeFarLocation;
2796}
2797
2798GLint Program::getDxDepthLocation() const
2799{
2800 return mDxDepthLocation;
2801}
2802
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002803GLint Program::getDxViewportLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002804{
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002805 return mDxViewportLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002806}
2807
2808GLint Program::getDxHalfPixelSizeLocation() const
2809{
2810 return mDxHalfPixelSizeLocation;
2811}
2812
2813GLint Program::getDxFrontCCWLocation() const
2814{
2815 return mDxFrontCCWLocation;
2816}
2817
2818GLint Program::getDxPointsOrLinesLocation() const
2819{
2820 return mDxPointsOrLinesLocation;
2821}
2822
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002823}