blob: 4597a08f2a2ac99df850abd30130a24aa18a9c4f [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
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +0000206 if (logicalTextureUnit >= 0 && logicalTextureUnit < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000207 {
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.coma3bbfd42010-06-07 02:06:09 +0000222GLint Program::getUniformLocation(const char *name, bool decorated)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223{
daniel@transgaming.comce864422010-11-18 13:16:49 +0000224 std::string _name = decorated ? name : decorate(name);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000225 int subscript = 0;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000226
daniel@transgaming.comce864422010-11-18 13:16:49 +0000227 // Strip any trailing array operator and retrieve the subscript
228 size_t open = _name.find_last_of('[');
229 size_t close = _name.find_last_of(']');
230 if (open != std::string::npos && close == _name.length() - 1)
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000231 {
daniel@transgaming.comce864422010-11-18 13:16:49 +0000232 subscript = atoi(_name.substr(open + 1).c_str());
233 _name.erase(open);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000234 }
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000235
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000236 unsigned int numUniforms = mUniformIndex.size();
237 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000238 {
daniel@transgaming.comce864422010-11-18 13:16:49 +0000239 if (mUniformIndex[location].name == _name &&
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000240 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000241 {
242 return location;
243 }
244 }
245
246 return -1;
247}
248
249bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
250{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000251 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000252 {
253 return false;
254 }
255
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000256 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000257 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000258
259 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000260 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000261 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000262
263 if (arraySize == 1 && count > 1)
264 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
265
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000266 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000267
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000268 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
269 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000270 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000271 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000272 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000273 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000274
275 if (arraySize == 1 && count > 1)
276 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000277
278 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000279 GLboolean *boolParams = new GLboolean[count];
280
281 for (int i = 0; i < count; ++i)
282 {
283 if (v[i] == 0.0f)
284 {
285 boolParams[i] = GL_FALSE;
286 }
287 else
288 {
289 boolParams[i] = GL_TRUE;
290 }
291 }
292
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000293 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
294 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000295
296 delete [] boolParams;
297 }
298 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000299 {
300 return false;
301 }
302
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000303 return true;
304}
305
306bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
307{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000308 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000309 {
310 return false;
311 }
312
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000313 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000314 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000315
316 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000317 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000318 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000319
320 if (arraySize == 1 && count > 1)
321 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
322
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000323 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000324
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000325 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
326 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000327 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000328 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000329 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000330 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000331
332 if (arraySize == 1 && count > 1)
333 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
334
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000335 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
336
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000337 GLboolean *boolParams = new GLboolean[count * 2];
338
339 for (int i = 0; i < count * 2; ++i)
340 {
341 if (v[i] == 0.0f)
342 {
343 boolParams[i] = GL_FALSE;
344 }
345 else
346 {
347 boolParams[i] = GL_TRUE;
348 }
349 }
350
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000351 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
352 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000353
354 delete [] boolParams;
355 }
356 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000357 {
358 return false;
359 }
360
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000361 return true;
362}
363
364bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
365{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000366 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000367 {
368 return false;
369 }
370
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000371 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000372 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000373
374 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000375 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000376 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000377
378 if (arraySize == 1 && count > 1)
379 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
380
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000381 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000382
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000383 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
384 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000385 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000386 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000387 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000388 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000389
390 if (arraySize == 1 && count > 1)
391 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
392
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000393 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000394 GLboolean *boolParams = new GLboolean[count * 3];
395
396 for (int i = 0; i < count * 3; ++i)
397 {
398 if (v[i] == 0.0f)
399 {
400 boolParams[i] = GL_FALSE;
401 }
402 else
403 {
404 boolParams[i] = GL_TRUE;
405 }
406 }
407
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000408 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
409 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000410
411 delete [] boolParams;
412 }
413 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000414 {
415 return false;
416 }
417
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000418 return true;
419}
420
421bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
422{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000423 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000424 {
425 return false;
426 }
427
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000428 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000429 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000430
431 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000432 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000433 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000434
435 if (arraySize == 1 && count > 1)
436 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
437
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000438 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000439
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000440 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
441 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000442 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000443 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000444 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000445 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000446
447 if (arraySize == 1 && count > 1)
448 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
449
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000450 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000451 GLboolean *boolParams = new GLboolean[count * 4];
452
453 for (int i = 0; i < count * 4; ++i)
454 {
455 if (v[i] == 0.0f)
456 {
457 boolParams[i] = GL_FALSE;
458 }
459 else
460 {
461 boolParams[i] = GL_TRUE;
462 }
463 }
464
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000465 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
466 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000467
468 delete [] boolParams;
469 }
470 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000471 {
472 return false;
473 }
474
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000475 return true;
476}
477
478bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
479{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000480 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000481 {
482 return false;
483 }
484
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000485 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000486 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000487
488 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000489 {
490 return false;
491 }
492
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000493 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000494
495 if (arraySize == 1 && count > 1)
496 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
497
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000498 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000499
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000500 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
501 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000502
503 return true;
504}
505
506bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
507{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000508 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000509 {
510 return false;
511 }
512
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000513 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000514 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000515
516 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000517 {
518 return false;
519 }
520
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000521 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000522
523 if (arraySize == 1 && count > 1)
524 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
525
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000526 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000527
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000528 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
529 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000530
531 return true;
532}
533
534bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
535{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000536 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000537 {
538 return false;
539 }
540
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000541 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000542 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000543
544 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000545 {
546 return false;
547 }
548
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000549 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000550
551 if (arraySize == 1 && count > 1)
552 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
553
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000554 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000555
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000556 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
557 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000558
559 return true;
560}
561
562bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
563{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000564 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000565 {
566 return false;
567 }
568
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000569 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000570 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000571
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000572 if (targetUniform->type == GL_INT ||
573 targetUniform->type == GL_SAMPLER_2D ||
574 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000575 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000576 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000577
578 if (arraySize == 1 && count > 1)
579 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
580
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000581 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000582
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000583 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
584 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000585 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000586 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000587 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000588 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000589
590 if (arraySize == 1 && count > 1)
591 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
592
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000593 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000594 GLboolean *boolParams = new GLboolean[count];
595
596 for (int i = 0; i < count; ++i)
597 {
598 if (v[i] == 0)
599 {
600 boolParams[i] = GL_FALSE;
601 }
602 else
603 {
604 boolParams[i] = GL_TRUE;
605 }
606 }
607
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000608 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
609 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000610
611 delete [] boolParams;
612 }
613 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000614 {
615 return false;
616 }
617
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000618 return true;
619}
620
621bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
622{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000623 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000624 {
625 return false;
626 }
627
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000628 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000629 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000630
631 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000632 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000633 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000634
635 if (arraySize == 1 && count > 1)
636 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
637
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000638 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000639
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000640 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
641 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000642 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000643 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000644 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000645 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000646
647 if (arraySize == 1 && count > 1)
648 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
649
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000650 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000651 GLboolean *boolParams = new GLboolean[count * 2];
652
653 for (int i = 0; i < count * 2; ++i)
654 {
655 if (v[i] == 0)
656 {
657 boolParams[i] = GL_FALSE;
658 }
659 else
660 {
661 boolParams[i] = GL_TRUE;
662 }
663 }
664
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000665 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
666 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000667
668 delete [] boolParams;
669 }
670 else
671 {
672 return false;
673 }
674
675 return true;
676}
677
678bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
679{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000680 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000681 {
682 return false;
683 }
684
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000685 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000686 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000687
688 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000689 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000690 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000691
692 if (arraySize == 1 && count > 1)
693 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
694
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000695 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000696
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000697 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
698 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000699 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000700 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000701 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000702 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000703
704 if (arraySize == 1 && count > 1)
705 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
706
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000707 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000708 GLboolean *boolParams = new GLboolean[count * 3];
709
710 for (int i = 0; i < count * 3; ++i)
711 {
712 if (v[i] == 0)
713 {
714 boolParams[i] = GL_FALSE;
715 }
716 else
717 {
718 boolParams[i] = GL_TRUE;
719 }
720 }
721
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000722 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
723 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000724
725 delete [] boolParams;
726 }
727 else
728 {
729 return false;
730 }
731
732 return true;
733}
734
735bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
736{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000737 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000738 {
739 return false;
740 }
741
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000742 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000743 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000744
745 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000746 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000747 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000748
749 if (arraySize == 1 && count > 1)
750 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
751
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000752 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000753
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000754 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
755 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000756 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000757 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000758 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000759 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000760
761 if (arraySize == 1 && count > 1)
762 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
763
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000764 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000765 GLboolean *boolParams = new GLboolean[count * 4];
766
767 for (int i = 0; i < count * 4; ++i)
768 {
769 if (v[i] == 0)
770 {
771 boolParams[i] = GL_FALSE;
772 }
773 else
774 {
775 boolParams[i] = GL_TRUE;
776 }
777 }
778
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000779 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
780 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000781
782 delete [] boolParams;
783 }
784 else
785 {
786 return false;
787 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000788
789 return true;
790}
791
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000792bool Program::getUniformfv(GLint location, GLfloat *params)
793{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000794 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000795 {
796 return false;
797 }
798
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000799 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000800
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000801 unsigned int count = UniformComponentCount(targetUniform->type);
802
803 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000804 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000805 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000806 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000807 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000808
809 for (unsigned int i = 0; i < count; ++i)
810 {
811 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
812 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000813 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000814 break;
815 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000816 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
817 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000818 break;
819 case GL_INT:
820 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000821 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000822
823 for (unsigned int i = 0; i < count; ++i)
824 {
825 params[i] = (float)intParams[i];
826 }
827 }
828 break;
829 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000830 }
831
832 return true;
833}
834
835bool Program::getUniformiv(GLint location, GLint *params)
836{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000837 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000838 {
839 return false;
840 }
841
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000842 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000843
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000844 unsigned int count = UniformComponentCount(targetUniform->type);
845
846 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000847 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000848 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000849 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000850 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000851
852 for (unsigned int i = 0; i < count; ++i)
853 {
854 params[i] = (GLint)boolParams[i];
855 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000856 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000857 break;
858 case GL_FLOAT:
859 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000860 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000861
862 for (unsigned int i = 0; i < count; ++i)
863 {
864 params[i] = (GLint)floatParams[i];
865 }
866 }
867 break;
868 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000869 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
870 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000871 break;
872 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000873 }
874
875 return true;
876}
877
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000878void Program::dirtyAllUniforms()
879{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000880 unsigned int numUniforms = mUniforms.size();
881 for (unsigned int index = 0; index < numUniforms; index++)
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000882 {
883 mUniforms[index]->dirty = true;
884 }
885}
886
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000887// Applies all the uniforms set for this program object to the Direct3D 9 device
888void Program::applyUniforms()
889{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000890 unsigned int numUniforms = mUniformIndex.size();
891 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000892 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000893 if (mUniformIndex[location].element != 0)
894 {
895 continue;
896 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000897
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000898 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
899
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000900 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000901 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000902 int arraySize = targetUniform->arraySize;
903 GLfloat *f = (GLfloat*)targetUniform->data;
904 GLint *i = (GLint*)targetUniform->data;
905 GLboolean *b = (GLboolean*)targetUniform->data;
906
907 switch (targetUniform->type)
908 {
909 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
910 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
911 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
912 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
913 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
914 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
915 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
916 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
917 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
918 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
919 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000920 case GL_SAMPLER_2D:
921 case GL_SAMPLER_CUBE:
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000922 case GL_INT: applyUniform1iv(location, arraySize, i); break;
923 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
924 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
925 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
926 default:
927 UNREACHABLE();
928 }
929
930 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000931 }
932 }
933}
934
935// Compiles the HLSL code of the attached shaders into executable binaries
936ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
937{
938 if (!hlsl)
939 {
940 return NULL;
941 }
942
943 ID3DXBuffer *binary = NULL;
944 ID3DXBuffer *errorMessage = NULL;
945
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000946 DWORD result;
947 if (perfActive())
948 {
949 DWORD flags = D3DXSHADER_DEBUG;
950#ifndef NDEBUG
951 flags |= D3DXSHADER_SKIPOPTIMIZATION;
952#endif
953
954 std::string sourcePath = getTempPath();
955 std::string sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
956 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
957
958 result = D3DXCompileShader(sourceText.c_str(), sourceText.size(), NULL, NULL, "main", profile, flags, &binary, &errorMessage, constantTable);
959 }
960 else
961 {
962 result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, NULL, "main", profile, 0, &binary, &errorMessage, constantTable);
963 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000964
965 if (SUCCEEDED(result))
966 {
967 return binary;
968 }
969
970 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
971 {
972 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
973 }
974
975 if (errorMessage)
976 {
977 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000978
daniel@transgaming.com0df16872010-05-12 16:51:08 +0000979 appendToInfoLog("%s\n", message);
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000980 TRACE("\n%s", hlsl);
981 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000982 }
983
984 return NULL;
985}
986
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000987// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
988// Returns the number of used varying registers, or -1 if unsuccesful
989int Program::packVaryings(const Varying *packing[][4])
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000990{
daniel@transgaming.com396c6432010-11-26 16:26:12 +0000991 Context *context = getContext();
992 const int maxVaryingVectors = context->getMaximumVaryingVectors();
993
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000994 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000995 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000996 int n = VariableRowCount(varying->type) * varying->size;
997 int m = VariableColumnCount(varying->type);
998 bool success = false;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000999
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001000 if (m == 2 || m == 3 || m == 4)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001001 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001002 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001003 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001004 bool available = true;
1005
1006 for (int y = 0; y < n && available; y++)
1007 {
1008 for (int x = 0; x < m && available; x++)
1009 {
1010 if (packing[r + y][x])
1011 {
1012 available = false;
1013 }
1014 }
1015 }
1016
1017 if (available)
1018 {
1019 varying->reg = r;
1020 varying->col = 0;
1021
1022 for (int y = 0; y < n; y++)
1023 {
1024 for (int x = 0; x < m; x++)
1025 {
1026 packing[r + y][x] = &*varying;
1027 }
1028 }
1029
1030 success = true;
1031 }
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001032 }
1033
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001034 if (!success && m == 2)
1035 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001036 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001037 {
1038 bool available = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001039
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001040 for (int y = 0; y < n && available; y++)
1041 {
1042 for (int x = 2; x < 4 && available; x++)
1043 {
1044 if (packing[r + y][x])
1045 {
1046 available = false;
1047 }
1048 }
1049 }
1050
1051 if (available)
1052 {
1053 varying->reg = r;
1054 varying->col = 2;
1055
1056 for (int y = 0; y < n; y++)
1057 {
1058 for (int x = 2; x < 4; x++)
1059 {
1060 packing[r + y][x] = &*varying;
1061 }
1062 }
1063
1064 success = true;
1065 }
1066 }
1067 }
1068 }
1069 else if (m == 1)
1070 {
1071 int space[4] = {0};
1072
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001073 for (int y = 0; y < maxVaryingVectors; y++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001074 {
1075 for (int x = 0; x < 4; x++)
1076 {
1077 space[x] += packing[y][x] ? 0 : 1;
1078 }
1079 }
1080
1081 int column = 0;
1082
1083 for (int x = 0; x < 4; x++)
1084 {
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001085 if (space[x] >= n && space[x] < space[column])
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001086 {
1087 column = x;
1088 }
1089 }
1090
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001091 if (space[column] >= n)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001092 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001093 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001094 {
1095 if (!packing[r][column])
1096 {
1097 varying->reg = r;
1098
1099 for (int y = r; y < r + n; y++)
1100 {
1101 packing[y][column] = &*varying;
1102 }
1103
1104 break;
1105 }
1106 }
1107
1108 varying->col = column;
1109
1110 success = true;
1111 }
1112 }
1113 else UNREACHABLE();
1114
1115 if (!success)
1116 {
1117 appendToInfoLog("Could not pack varying %s", varying->name.c_str());
1118
1119 return -1;
1120 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001121 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001122
1123 // Return the number of used registers
1124 int registers = 0;
1125
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001126 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001127 {
1128 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1129 {
1130 registers++;
1131 }
1132 }
1133
1134 return registers;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001135}
1136
1137bool Program::linkVaryings()
1138{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001139 if (mPixelHLSL.empty() || mVertexHLSL.empty())
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001140 {
1141 return false;
1142 }
1143
daniel@transgaming.com97750022011-02-11 13:23:13 +00001144 // Reset the varying register assignments
1145 for (VaryingList::iterator fragVar = mFragmentShader->varyings.begin(); fragVar != mFragmentShader->varyings.end(); fragVar++)
1146 {
1147 fragVar->reg = -1;
1148 fragVar->col = -1;
1149 }
1150
1151 for (VaryingList::iterator vtxVar = mVertexShader->varyings.begin(); vtxVar != mVertexShader->varyings.end(); vtxVar++)
1152 {
1153 vtxVar->reg = -1;
1154 vtxVar->col = -1;
1155 }
1156
1157 // Map the varyings to the register file
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001158 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001159 int registers = packVaryings(packing);
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001160
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001161 if (registers < 0)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001162 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001163 return false;
1164 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001165
daniel@transgaming.com97750022011-02-11 13:23:13 +00001166 // Write the HLSL input/output declarations
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001167 Context *context = getContext();
1168 const bool sm3 = context->supportsShaderModel3();
1169 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1170
1171 if (registers == maxVaryingVectors && mFragmentShader->mUsesFragCoord)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001172 {
1173 appendToInfoLog("No varying registers left to support gl_FragCoord");
1174
1175 return false;
1176 }
1177
1178 for (VaryingList::iterator input = mFragmentShader->varyings.begin(); input != mFragmentShader->varyings.end(); input++)
1179 {
1180 bool matched = false;
1181
1182 for (VaryingList::iterator output = mVertexShader->varyings.begin(); output != mVertexShader->varyings.end(); output++)
1183 {
1184 if (output->name == input->name)
1185 {
1186 if (output->type != input->type || output->size != input->size)
1187 {
1188 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
1189
1190 return false;
1191 }
1192
1193 output->reg = input->reg;
1194 output->col = input->col;
1195
1196 matched = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001197 break;
1198 }
1199 }
1200
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001201 if (!matched)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001202 {
daniel@transgaming.com97750022011-02-11 13:23:13 +00001203 appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001204
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001205 return false;
1206 }
1207 }
1208
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001209 std::string varyingSemantic = (sm3 ? "COLOR" : "TEXCOORD");
1210
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001211 mVertexHLSL += "struct VS_INPUT\n"
1212 "{\n";
1213
1214 int semanticIndex = 0;
1215 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1216 {
1217 switch (attribute->type)
1218 {
1219 case GL_FLOAT: mVertexHLSL += " float "; break;
1220 case GL_FLOAT_VEC2: mVertexHLSL += " float2 "; break;
1221 case GL_FLOAT_VEC3: mVertexHLSL += " float3 "; break;
1222 case GL_FLOAT_VEC4: mVertexHLSL += " float4 "; break;
1223 case GL_FLOAT_MAT2: mVertexHLSL += " float2x2 "; break;
1224 case GL_FLOAT_MAT3: mVertexHLSL += " float3x3 "; break;
1225 case GL_FLOAT_MAT4: mVertexHLSL += " float4x4 "; break;
1226 default: UNREACHABLE();
1227 }
1228
1229 mVertexHLSL += decorate(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1230
1231 semanticIndex += VariableRowCount(attribute->type);
1232 }
1233
1234 mVertexHLSL += "};\n"
1235 "\n"
1236 "struct VS_OUTPUT\n"
1237 "{\n"
1238 " float4 gl_Position : POSITION;\n";
1239
1240 for (int r = 0; r < registers; r++)
1241 {
1242 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1243
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001244 mVertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001245 }
1246
1247 if (mFragmentShader->mUsesFragCoord)
1248 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001249 mVertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1250 }
1251
1252 if (mVertexShader->mUsesPointSize && sm3)
1253 {
1254 mVertexHLSL += " float gl_PointSize : PSIZE;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001255 }
1256
1257 mVertexHLSL += "};\n"
1258 "\n"
1259 "VS_OUTPUT main(VS_INPUT input)\n"
1260 "{\n";
1261
1262 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1263 {
1264 mVertexHLSL += " " + decorate(attribute->name) + " = ";
1265
1266 if (VariableRowCount(attribute->type) > 1) // Matrix
1267 {
1268 mVertexHLSL += "transpose";
1269 }
1270
1271 mVertexHLSL += "(input." + decorate(attribute->name) + ");\n";
1272 }
1273
1274 mVertexHLSL += "\n"
1275 " gl_main();\n"
1276 "\n"
1277 " VS_OUTPUT output;\n"
1278 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001279 " output.gl_Position.y = gl_Position.y - dx_HalfPixelSize.y * gl_Position.w;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001280 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1281 " output.gl_Position.w = gl_Position.w;\n";
1282
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001283 if (mVertexShader->mUsesPointSize && sm3)
1284 {
1285 mVertexHLSL += " output.gl_PointSize = clamp(gl_PointSize, 1.0, " + str((int)ALIASED_POINT_SIZE_RANGE_MAX_SM3) + ");\n";
1286 }
1287
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001288 if (mFragmentShader->mUsesFragCoord)
1289 {
1290 mVertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1291 }
1292
1293 for (VaryingList::iterator varying = mVertexShader->varyings.begin(); varying != mVertexShader->varyings.end(); varying++)
1294 {
1295 if (varying->reg >= 0)
1296 {
1297 for (int i = 0; i < varying->size; i++)
1298 {
1299 int rows = VariableRowCount(varying->type);
1300
1301 for (int j = 0; j < rows; j++)
1302 {
1303 int r = varying->reg + i * rows + j;
1304 mVertexHLSL += " output.v" + str(r);
1305
1306 bool sharedRegister = false; // Register used by multiple varyings
1307
1308 for (int x = 0; x < 4; x++)
1309 {
1310 if (packing[r][x] && packing[r][x] != packing[r][0])
1311 {
1312 sharedRegister = true;
1313 break;
1314 }
1315 }
1316
1317 if(sharedRegister)
1318 {
1319 mVertexHLSL += ".";
1320
1321 for (int x = 0; x < 4; x++)
1322 {
1323 if (packing[r][x] == &*varying)
1324 {
1325 switch(x)
1326 {
1327 case 0: mVertexHLSL += "x"; break;
1328 case 1: mVertexHLSL += "y"; break;
1329 case 2: mVertexHLSL += "z"; break;
1330 case 3: mVertexHLSL += "w"; break;
1331 }
1332 }
1333 }
1334 }
1335
1336 mVertexHLSL += " = " + varying->name;
1337
1338 if (varying->array)
1339 {
1340 mVertexHLSL += "[" + str(i) + "]";
1341 }
1342
1343 if (rows > 1)
1344 {
1345 mVertexHLSL += "[" + str(j) + "]";
1346 }
1347
1348 mVertexHLSL += ";\n";
1349 }
1350 }
1351 }
1352 }
1353
1354 mVertexHLSL += "\n"
1355 " return output;\n"
1356 "}\n";
1357
1358 mPixelHLSL += "struct PS_INPUT\n"
1359 "{\n";
1360
1361 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1362 {
1363 if (varying->reg >= 0)
1364 {
1365 for (int i = 0; i < varying->size; i++)
1366 {
1367 int rows = VariableRowCount(varying->type);
1368 for (int j = 0; j < rows; j++)
1369 {
1370 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001371 mPixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001372 }
1373 }
1374 }
1375 else UNREACHABLE();
1376 }
1377
1378 if (mFragmentShader->mUsesFragCoord)
1379 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001380 mPixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001381 if (sm3) {
daniel@transgaming.com996675c2010-11-17 13:06:29 +00001382 mPixelHLSL += " float2 dx_VPos : VPOS;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001383 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001384 }
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001385
1386 if (mFragmentShader->mUsesPointCoord && sm3)
1387 {
1388 mPixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1389 }
1390
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001391 if (mFragmentShader->mUsesFrontFacing)
1392 {
1393 mPixelHLSL += " float vFace : VFACE;\n";
1394 }
1395
1396 mPixelHLSL += "};\n"
1397 "\n"
1398 "struct PS_OUTPUT\n"
1399 "{\n"
1400 " float4 gl_Color[1] : COLOR;\n"
1401 "};\n"
1402 "\n"
1403 "PS_OUTPUT main(PS_INPUT input)\n"
1404 "{\n";
1405
1406 if (mFragmentShader->mUsesFragCoord)
1407 {
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001408 mPixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1409 if (sm3) {
1410 mPixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001411 " gl_FragCoord.y = 2.0 * dx_Viewport.y - input.dx_VPos.y;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001412 } else {
1413 mPixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Viewport.x + dx_Viewport.z;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001414 " gl_FragCoord.y = -(input.gl_FragCoord.y * rhw) * dx_Viewport.y + dx_Viewport.w;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001415 }
1416 mPixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001417 " gl_FragCoord.w = rhw;\n";
1418 }
1419
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001420 if (mFragmentShader->mUsesPointCoord && sm3)
1421 {
apatrick@chromium.orgda4d0492011-01-22 00:16:10 +00001422 mPixelHLSL += " gl_PointCoord = input.gl_PointCoord;\n";
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001423 }
1424
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001425 if (mFragmentShader->mUsesFrontFacing)
1426 {
1427 mPixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1428 }
1429
1430 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1431 {
1432 if (varying->reg >= 0)
1433 {
1434 for (int i = 0; i < varying->size; i++)
1435 {
1436 int rows = VariableRowCount(varying->type);
1437 for (int j = 0; j < rows; j++)
1438 {
1439 std::string n = str(varying->reg + i * rows + j);
1440 mPixelHLSL += " " + varying->name;
1441
1442 if (varying->array)
1443 {
1444 mPixelHLSL += "[" + str(i) + "]";
1445 }
1446
1447 if (rows > 1)
1448 {
1449 mPixelHLSL += "[" + str(j) + "]";
1450 }
1451
1452 mPixelHLSL += " = input.v" + n + ";\n";
1453 }
1454 }
1455 }
1456 else UNREACHABLE();
1457 }
1458
1459 mPixelHLSL += "\n"
1460 " gl_main();\n"
1461 "\n"
1462 " PS_OUTPUT output;\n"
1463 " output.gl_Color[0] = gl_Color[0];\n"
1464 "\n"
1465 " return output;\n"
1466 "}\n";
1467
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001468 return true;
1469}
1470
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001471// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1472// compiling them into binaries, determining the attribute mappings, and collecting
1473// a list of uniforms
1474void Program::link()
1475{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001476 unlink();
1477
1478 if (!mFragmentShader || !mFragmentShader->isCompiled())
1479 {
1480 return;
1481 }
1482
1483 if (!mVertexShader || !mVertexShader->isCompiled())
1484 {
1485 return;
1486 }
1487
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001488 mPixelHLSL = mFragmentShader->getHLSL();
1489 mVertexHLSL = mVertexShader->getHLSL();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001490
1491 if (!linkVaryings())
1492 {
1493 return;
1494 }
1495
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001496 Context *context = getContext();
1497 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1498 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1499
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001500 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1501 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001502
1503 if (vertexBinary && pixelBinary)
1504 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001505 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001506 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1507 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1508
1509 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1510 {
1511 return error(GL_OUT_OF_MEMORY);
1512 }
1513
1514 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001515
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001516 vertexBinary->Release();
1517 pixelBinary->Release();
1518 vertexBinary = NULL;
1519 pixelBinary = NULL;
1520
1521 if (mVertexExecutable && mPixelExecutable)
1522 {
1523 if (!linkAttributes())
1524 {
1525 return;
1526 }
1527
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001528 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001529 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001530 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001531 }
1532
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001533 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001534 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001535 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001536 }
1537
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001538 // these uniforms are searched as already-decorated because gl_ and dx_
1539 // are reserved prefixes, and do not receive additional decoration
daniel@transgaming.com31754962010-11-28 02:02:52 +00001540 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange", true);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001541 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 {
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001663 for (unsigned int samplerIndex = constantDescription.RegisterIndex; samplerIndex < constantDescription.RegisterIndex + constantDescription.RegisterCount; samplerIndex++)
1664 {
1665 ASSERT(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001666
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001667 mSamplers[samplerIndex].active = true;
1668 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1669 mSamplers[samplerIndex].logicalTextureUnit = 0;
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001670 }
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 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001677 for (unsigned int arrayIndex = 0; arrayIndex < constantDescription.Elements; arrayIndex++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001678 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001679 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001680 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001681 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1682
1683 D3DXCONSTANT_DESC fieldDescription;
1684 UINT descriptionCount = 1;
1685
1686 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1687
1688 std::string structIndex = (constantDescription.Elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
1689
1690 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + structIndex + "."))
1691 {
1692 return false;
1693 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001694 }
1695 }
1696
1697 return true;
1698 }
1699 case D3DXPC_SCALAR:
1700 case D3DXPC_VECTOR:
1701 case D3DXPC_MATRIX_COLUMNS:
1702 case D3DXPC_OBJECT:
1703 return defineUniform(constantDescription, name + constantDescription.Name);
1704 default:
1705 UNREACHABLE();
1706 return false;
1707 }
1708}
1709
1710bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1711{
1712 Uniform *uniform = createUniform(constantDescription, name);
1713
1714 if(!uniform)
1715 {
1716 return false;
1717 }
1718
1719 // Check if already defined
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001720 GLint location = getUniformLocation(name.c_str(), true);
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001721 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001722
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001723 if (location >= 0)
1724 {
1725 delete uniform;
1726
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001727 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001728 {
1729 return false;
1730 }
1731 else
1732 {
1733 return true;
1734 }
1735 }
1736
1737 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001738 unsigned int uniformIndex = mUniforms.size() - 1;
1739
1740 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1741 {
1742 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1743 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001744
1745 return true;
1746}
1747
1748Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001749{
1750 if (constantDescription.Rows == 1) // Vectors and scalars
1751 {
1752 switch (constantDescription.Type)
1753 {
1754 case D3DXPT_SAMPLER2D:
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001755 switch (constantDescription.Columns)
1756 {
1757 case 1: return new Uniform(GL_SAMPLER_2D, name, constantDescription.Elements);
1758 default: UNREACHABLE();
1759 }
1760 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001761 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001762 switch (constantDescription.Columns)
1763 {
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001764 case 1: return new Uniform(GL_SAMPLER_CUBE, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001765 default: UNREACHABLE();
1766 }
1767 break;
1768 case D3DXPT_BOOL:
1769 switch (constantDescription.Columns)
1770 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001771 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1772 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1773 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1774 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001775 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001776 }
1777 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001778 case D3DXPT_INT:
1779 switch (constantDescription.Columns)
1780 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001781 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1782 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1783 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1784 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001785 default: UNREACHABLE();
1786 }
1787 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001788 case D3DXPT_FLOAT:
1789 switch (constantDescription.Columns)
1790 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001791 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1792 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1793 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1794 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001795 default: UNREACHABLE();
1796 }
1797 break;
1798 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001799 UNREACHABLE();
1800 }
1801 }
1802 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1803 {
1804 switch (constantDescription.Type)
1805 {
1806 case D3DXPT_FLOAT:
1807 switch (constantDescription.Rows)
1808 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001809 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1810 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1811 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001812 default: UNREACHABLE();
1813 }
1814 break;
1815 default: UNREACHABLE();
1816 }
1817 }
1818 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001819
1820 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001821}
1822
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001823// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001824std::string Program::decorate(const std::string &string)
1825{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001826 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001827 {
1828 return "_" + string;
1829 }
1830 else
1831 {
1832 return string;
1833 }
1834}
1835
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001836std::string Program::undecorate(const std::string &string)
1837{
1838 if (string.substr(0, 1) == "_")
1839 {
1840 return string.substr(1);
1841 }
1842 else
1843 {
1844 return string;
1845 }
1846}
1847
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001848bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1849{
1850 BOOL *vector = new BOOL[count];
1851 for (int i = 0; i < count; i++)
1852 {
1853 if (v[i] == GL_FALSE)
1854 vector[i] = 0;
1855 else
1856 vector[i] = 1;
1857 }
1858
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001859 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1860
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001861 D3DXHANDLE constantPS;
1862 D3DXHANDLE constantVS;
1863 getConstantHandles(targetUniform, &constantPS, &constantVS);
1864
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001865 IDirect3DDevice9 *device = getDevice();
1866
1867 if (constantPS)
1868 {
1869 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1870 }
1871
1872 if (constantVS)
1873 {
1874 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1875 }
1876
1877 delete [] vector;
1878
1879 return true;
1880}
1881
1882bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1883{
1884 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1885
1886 for (int i = 0; i < count; i++)
1887 {
1888 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1889 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1890
1891 v += 2;
1892 }
1893
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001894 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1895
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001896 D3DXHANDLE constantPS;
1897 D3DXHANDLE constantVS;
1898 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001899 IDirect3DDevice9 *device = getDevice();
1900
1901 if (constantPS)
1902 {
1903 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1904 }
1905
1906 if (constantVS)
1907 {
1908 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1909 }
1910
1911 delete[] vector;
1912
1913 return true;
1914}
1915
1916bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1917{
1918 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1919
1920 for (int i = 0; i < count; i++)
1921 {
1922 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1923 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1924 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1925
1926 v += 3;
1927 }
1928
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001929 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1930
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001931 D3DXHANDLE constantPS;
1932 D3DXHANDLE constantVS;
1933 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001934 IDirect3DDevice9 *device = getDevice();
1935
1936 if (constantPS)
1937 {
1938 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1939 }
1940
1941 if (constantVS)
1942 {
1943 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1944 }
1945
1946 delete[] vector;
1947
1948 return true;
1949}
1950
1951bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1952{
1953 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1954
1955 for (int i = 0; i < count; i++)
1956 {
1957 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1958 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1959 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1960 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1961
1962 v += 3;
1963 }
1964
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001965 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1966
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001967 D3DXHANDLE constantPS;
1968 D3DXHANDLE constantVS;
1969 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001970 IDirect3DDevice9 *device = getDevice();
1971
1972 if (constantPS)
1973 {
1974 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1975 }
1976
1977 if (constantVS)
1978 {
1979 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1980 }
1981
1982 delete [] vector;
1983
1984 return true;
1985}
1986
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001987bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1988{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001989 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1990
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001991 D3DXHANDLE constantPS;
1992 D3DXHANDLE constantVS;
1993 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001994 IDirect3DDevice9 *device = getDevice();
1995
1996 if (constantPS)
1997 {
1998 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1999 }
2000
2001 if (constantVS)
2002 {
2003 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
2004 }
2005
2006 return true;
2007}
2008
2009bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
2010{
2011 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2012
2013 for (int i = 0; i < count; i++)
2014 {
2015 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
2016
2017 v += 2;
2018 }
2019
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002020 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2021
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002022 D3DXHANDLE constantPS;
2023 D3DXHANDLE constantVS;
2024 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002025 IDirect3DDevice9 *device = getDevice();
2026
2027 if (constantPS)
2028 {
2029 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2030 }
2031
2032 if (constantVS)
2033 {
2034 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2035 }
2036
2037 delete[] vector;
2038
2039 return true;
2040}
2041
2042bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
2043{
2044 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2045
2046 for (int i = 0; i < count; i++)
2047 {
2048 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
2049
2050 v += 3;
2051 }
2052
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002053 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2054
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002055 D3DXHANDLE constantPS;
2056 D3DXHANDLE constantVS;
2057 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002058 IDirect3DDevice9 *device = getDevice();
2059
2060 if (constantPS)
2061 {
2062 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2063 }
2064
2065 if (constantVS)
2066 {
2067 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2068 }
2069
2070 delete[] vector;
2071
2072 return true;
2073}
2074
2075bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
2076{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002077 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2078
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002079 D3DXHANDLE constantPS;
2080 D3DXHANDLE constantVS;
2081 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002082 IDirect3DDevice9 *device = getDevice();
2083
2084 if (constantPS)
2085 {
2086 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
2087 }
2088
2089 if (constantVS)
2090 {
2091 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
2092 }
2093
2094 return true;
2095}
2096
2097bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
2098{
2099 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2100
2101 for (int i = 0; i < count; i++)
2102 {
2103 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
2104 value[1], value[3], 0, 0,
2105 0, 0, 1, 0,
2106 0, 0, 0, 1);
2107
2108 value += 4;
2109 }
2110
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002111 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2112
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002113 D3DXHANDLE constantPS;
2114 D3DXHANDLE constantVS;
2115 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002116 IDirect3DDevice9 *device = getDevice();
2117
2118 if (constantPS)
2119 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002120 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002121 }
2122
2123 if (constantVS)
2124 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002125 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002126 }
2127
2128 delete[] matrix;
2129
2130 return true;
2131}
2132
2133bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
2134{
2135 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2136
2137 for (int i = 0; i < count; i++)
2138 {
2139 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
2140 value[1], value[4], value[7], 0,
2141 value[2], value[5], value[8], 0,
2142 0, 0, 0, 1);
2143
2144 value += 9;
2145 }
2146
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002147 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2148
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002149 D3DXHANDLE constantPS;
2150 D3DXHANDLE constantVS;
2151 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002152 IDirect3DDevice9 *device = getDevice();
2153
2154 if (constantPS)
2155 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002156 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002157 }
2158
2159 if (constantVS)
2160 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002161 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002162 }
2163
2164 delete[] matrix;
2165
2166 return true;
2167}
2168
2169bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
2170{
2171 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2172
2173 for (int i = 0; i < count; i++)
2174 {
2175 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
2176 value[1], value[5], value[9], value[13],
2177 value[2], value[6], value[10], value[14],
2178 value[3], value[7], value[11], value[15]);
2179
2180 value += 16;
2181 }
2182
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002183 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2184
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002185 D3DXHANDLE constantPS;
2186 D3DXHANDLE constantVS;
2187 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002188 IDirect3DDevice9 *device = getDevice();
2189
2190 if (constantPS)
2191 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002192 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002193 }
2194
2195 if (constantVS)
2196 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002197 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002198 }
2199
2200 delete[] matrix;
2201
2202 return true;
2203}
2204
2205bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
2206{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002207 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2208
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002209 D3DXHANDLE constantPS;
2210 D3DXHANDLE constantVS;
2211 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002212 IDirect3DDevice9 *device = getDevice();
2213
2214 if (constantPS)
2215 {
2216 D3DXCONSTANT_DESC constantDescription;
2217 UINT descriptionCount = 1;
2218 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
2219
daniel@transgaming.com2884b782010-03-08 21:30:48 +00002220 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002221 {
2222 return false;
2223 }
2224
2225 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2226 {
2227 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
2228
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002229 for (int i = 0; i < count; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002230 {
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002231 unsigned int samplerIndex = firstIndex + i;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002232
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002233 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002234 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002235 ASSERT(mSamplers[samplerIndex].active);
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002236 mSamplers[samplerIndex].logicalTextureUnit = v[i];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002237 }
2238 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002239
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002240 return true;
2241 }
2242 }
2243
2244 if (constantPS)
2245 {
2246 mConstantTablePS->SetIntArray(device, constantPS, v, count);
2247 }
2248
2249 if (constantVS)
2250 {
2251 mConstantTableVS->SetIntArray(device, constantVS, v, count);
2252 }
2253
2254 return true;
2255}
2256
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002257bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
2258{
2259 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2260
2261 for (int i = 0; i < count; i++)
2262 {
2263 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2264
2265 v += 2;
2266 }
2267
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002268 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2269
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002270 D3DXHANDLE constantPS;
2271 D3DXHANDLE constantVS;
2272 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002273 IDirect3DDevice9 *device = getDevice();
2274
2275 if (constantPS)
2276 {
2277 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2278 }
2279
2280 if (constantVS)
2281 {
2282 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2283 }
2284
2285 delete[] vector;
2286
2287 return true;
2288}
2289
2290bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
2291{
2292 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2293
2294 for (int i = 0; i < count; i++)
2295 {
2296 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2297
2298 v += 3;
2299 }
2300
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002301 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2302
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002303 D3DXHANDLE constantPS;
2304 D3DXHANDLE constantVS;
2305 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002306 IDirect3DDevice9 *device = getDevice();
2307
2308 if (constantPS)
2309 {
2310 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2311 }
2312
2313 if (constantVS)
2314 {
2315 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2316 }
2317
2318 delete[] vector;
2319
2320 return true;
2321}
2322
2323bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
2324{
2325 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2326
2327 for (int i = 0; i < count; i++)
2328 {
2329 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2330
2331 v += 4;
2332 }
2333
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002334 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2335
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002336 D3DXHANDLE constantPS;
2337 D3DXHANDLE constantVS;
2338 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002339 IDirect3DDevice9 *device = getDevice();
2340
2341 if (constantPS)
2342 {
2343 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2344 }
2345
2346 if (constantVS)
2347 {
2348 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2349 }
2350
2351 delete [] vector;
2352
2353 return true;
2354}
2355
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002356void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002357{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002358 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002359 {
2360 return;
2361 }
2362
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002363 char info[1024];
2364
2365 va_list vararg;
2366 va_start(vararg, format);
2367 vsnprintf(info, sizeof(info), format, vararg);
2368 va_end(vararg);
2369
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002370 size_t infoLength = strlen(info);
2371
2372 if (!mInfoLog)
2373 {
2374 mInfoLog = new char[infoLength + 1];
2375 strcpy(mInfoLog, info);
2376 }
2377 else
2378 {
2379 size_t logLength = strlen(mInfoLog);
2380 char *newLog = new char[logLength + infoLength + 1];
2381 strcpy(newLog, mInfoLog);
2382 strcpy(newLog + logLength, info);
2383
2384 delete[] mInfoLog;
2385 mInfoLog = newLog;
2386 }
2387}
2388
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002389void Program::resetInfoLog()
2390{
2391 if (mInfoLog)
2392 {
2393 delete [] mInfoLog;
daniel@transgaming.com6a20d102010-08-31 13:54:27 +00002394 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002395 }
2396}
2397
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002398// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
2399void Program::unlink(bool destroy)
2400{
2401 if (destroy) // Object being destructed
2402 {
2403 if (mFragmentShader)
2404 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002405 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002406 mFragmentShader = NULL;
2407 }
2408
2409 if (mVertexShader)
2410 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002411 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002412 mVertexShader = NULL;
2413 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002414 }
2415
2416 if (mPixelExecutable)
2417 {
2418 mPixelExecutable->Release();
2419 mPixelExecutable = NULL;
2420 }
2421
2422 if (mVertexExecutable)
2423 {
2424 mVertexExecutable->Release();
2425 mVertexExecutable = NULL;
2426 }
2427
2428 if (mConstantTablePS)
2429 {
2430 mConstantTablePS->Release();
2431 mConstantTablePS = NULL;
2432 }
2433
2434 if (mConstantTableVS)
2435 {
2436 mConstantTableVS->Release();
2437 mConstantTableVS = NULL;
2438 }
2439
2440 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2441 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002442 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002443 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002444 }
2445
2446 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2447 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00002448 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002449 }
2450
2451 while (!mUniforms.empty())
2452 {
2453 delete mUniforms.back();
2454 mUniforms.pop_back();
2455 }
2456
daniel@transgaming.com31754962010-11-28 02:02:52 +00002457 mDxDepthRangeLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002458 mDxDepthLocation = -1;
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002459 mDxViewportLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002460 mDxHalfPixelSizeLocation = -1;
2461 mDxFrontCCWLocation = -1;
2462 mDxPointsOrLinesLocation = -1;
2463
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002464 mUniformIndex.clear();
2465
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002466 mPixelHLSL.clear();
2467 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002468
2469 delete[] mInfoLog;
2470 mInfoLog = NULL;
2471
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002472 mLinked = false;
2473}
2474
2475bool Program::isLinked()
2476{
2477 return mLinked;
2478}
2479
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002480bool Program::isValidated() const
2481{
2482 return mValidated;
2483}
2484
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002485void Program::release()
2486{
2487 mRefCount--;
2488
2489 if (mRefCount == 0 && mDeleteStatus)
2490 {
2491 mResourceManager->deleteProgram(mHandle);
2492 }
2493}
2494
2495void Program::addRef()
2496{
2497 mRefCount++;
2498}
2499
2500unsigned int Program::getRefCount() const
2501{
2502 return mRefCount;
2503}
2504
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002505unsigned int Program::getSerial() const
2506{
2507 return mSerial;
2508}
2509
2510unsigned int Program::issueSerial()
2511{
2512 return mCurrentSerial++;
2513}
2514
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002515int Program::getInfoLogLength() const
2516{
2517 if (!mInfoLog)
2518 {
2519 return 0;
2520 }
2521 else
2522 {
2523 return strlen(mInfoLog) + 1;
2524 }
2525}
2526
2527void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2528{
2529 int index = 0;
2530
2531 if (mInfoLog)
2532 {
2533 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2534 {
2535 infoLog[index] = mInfoLog[index];
2536 index++;
2537 }
2538 }
2539
2540 if (bufSize)
2541 {
2542 infoLog[index] = '\0';
2543 }
2544
2545 if (length)
2546 {
2547 *length = index;
2548 }
2549}
2550
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002551void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2552{
2553 int total = 0;
2554
2555 if (mVertexShader)
2556 {
2557 if (total < maxCount)
2558 {
2559 shaders[total] = mVertexShader->getHandle();
2560 }
2561
2562 total++;
2563 }
2564
2565 if (mFragmentShader)
2566 {
2567 if (total < maxCount)
2568 {
2569 shaders[total] = mFragmentShader->getHandle();
2570 }
2571
2572 total++;
2573 }
2574
2575 if (count)
2576 {
2577 *count = total;
2578 }
2579}
2580
daniel@transgaming.com85423182010-04-22 13:35:27 +00002581void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2582{
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002583 // Skip over inactive attributes
2584 unsigned int activeAttribute = 0;
2585 unsigned int attribute;
2586 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
daniel@transgaming.com85423182010-04-22 13:35:27 +00002587 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002588 if (mLinkedAttribute[attribute].name.empty())
daniel@transgaming.com85423182010-04-22 13:35:27 +00002589 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002590 continue;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002591 }
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002592
2593 if (activeAttribute == index)
2594 {
2595 break;
2596 }
2597
2598 activeAttribute++;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002599 }
2600
2601 if (bufsize > 0)
2602 {
2603 const char *string = mLinkedAttribute[attribute].name.c_str();
2604
2605 strncpy(name, string, bufsize);
2606 name[bufsize - 1] = '\0';
2607
2608 if (length)
2609 {
2610 *length = strlen(name);
2611 }
2612 }
2613
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002614 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002615
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002616 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002617}
2618
2619GLint Program::getActiveAttributeCount()
2620{
2621 int count = 0;
2622
2623 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2624 {
2625 if (!mLinkedAttribute[attributeIndex].name.empty())
2626 {
2627 count++;
2628 }
2629 }
2630
2631 return count;
2632}
2633
2634GLint Program::getActiveAttributeMaxLength()
2635{
2636 int maxLength = 0;
2637
2638 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2639 {
2640 if (!mLinkedAttribute[attributeIndex].name.empty())
2641 {
2642 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2643 }
2644 }
2645
2646 return maxLength;
2647}
2648
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002649void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2650{
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002651 // Skip over internal uniforms
2652 unsigned int activeUniform = 0;
2653 unsigned int uniform;
2654 for (uniform = 0; uniform < mUniforms.size(); uniform++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002655 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002656 if (mUniforms[uniform]->name.substr(0, 3) == "dx_")
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002657 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002658 continue;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002659 }
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002660
2661 if (activeUniform == index)
2662 {
2663 break;
2664 }
2665
2666 activeUniform++;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002667 }
2668
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002669 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2670
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002671 if (bufsize > 0)
2672 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002673 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002674
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002675 if (mUniforms[uniform]->arraySize != 1)
2676 {
2677 string += "[0]";
2678 }
2679
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002680 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002681 name[bufsize - 1] = '\0';
2682
2683 if (length)
2684 {
2685 *length = strlen(name);
2686 }
2687 }
2688
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002689 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002690
2691 *type = mUniforms[uniform]->type;
2692}
2693
2694GLint Program::getActiveUniformCount()
2695{
2696 int count = 0;
2697
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002698 unsigned int numUniforms = mUniforms.size();
2699 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002700 {
2701 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2702 {
2703 count++;
2704 }
2705 }
2706
2707 return count;
2708}
2709
2710GLint Program::getActiveUniformMaxLength()
2711{
2712 int maxLength = 0;
2713
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002714 unsigned int numUniforms = mUniforms.size();
2715 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002716 {
2717 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2718 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002719 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002720 }
2721 }
2722
2723 return maxLength;
2724}
2725
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002726void Program::flagForDeletion()
2727{
2728 mDeleteStatus = true;
2729}
2730
2731bool Program::isFlaggedForDeletion() const
2732{
2733 return mDeleteStatus;
2734}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002735
2736void Program::validate()
2737{
2738 resetInfoLog();
2739
2740 if (!isLinked())
2741 {
2742 appendToInfoLog("Program has not been successfully linked.");
2743 mValidated = false;
2744 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002745 else
2746 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002747 applyUniforms();
2748 if (!validateSamplers())
2749 {
2750 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2751 mValidated = false;
2752 }
2753 else
2754 {
2755 mValidated = true;
2756 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002757 }
2758}
2759
2760bool Program::validateSamplers() const
2761{
2762 // if any two active samplers in a program are of different types, but refer to the same
2763 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2764 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2765 std::map<int, SamplerType> samplerMap;
2766 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2767 {
2768 if (mSamplers[i].active)
2769 {
2770 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2771 {
2772 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2773 return false;
2774 }
2775 else
2776 {
2777 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2778 }
2779 }
2780 }
2781
2782 return true;
2783}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002784
2785void Program::getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS)
2786{
2787 if (!targetUniform->handlesSet)
2788 {
2789 targetUniform->psHandle = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2790 targetUniform->vsHandle = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
2791 targetUniform->handlesSet = true;
2792 }
2793
2794 *constantPS = targetUniform->psHandle;
2795 *constantVS = targetUniform->vsHandle;
2796}
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002797
daniel@transgaming.com31754962010-11-28 02:02:52 +00002798GLint Program::getDxDepthRangeLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002799{
daniel@transgaming.com31754962010-11-28 02:02:52 +00002800 return mDxDepthRangeLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002801}
2802
2803GLint Program::getDxDepthLocation() const
2804{
2805 return mDxDepthLocation;
2806}
2807
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002808GLint Program::getDxViewportLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002809{
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002810 return mDxViewportLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002811}
2812
2813GLint Program::getDxHalfPixelSizeLocation() const
2814{
2815 return mDxHalfPixelSizeLocation;
2816}
2817
2818GLint Program::getDxFrontCCWLocation() const
2819{
2820 return mDxFrontCCWLocation;
2821}
2822
2823GLint Program::getDxPointsOrLinesLocation() const
2824{
2825 return mDxPointsOrLinesLocation;
2826}
2827
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002828}