blob: 6ad34c6fefcad0c81df343900852c639c2f38e90 [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
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +000018#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
19#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3
20#endif
21
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000022namespace gl
23{
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000024unsigned int Program::mCurrentSerial = 1;
25
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000026std::string str(int i)
27{
28 char buffer[20];
29 sprintf(buffer, "%d", i);
30 return buffer;
31}
32
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000033Uniform::Uniform(GLenum type, const std::string &name, unsigned int arraySize) : type(type), name(name), arraySize(arraySize)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000034{
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000035 int bytes = UniformTypeSize(type) * arraySize;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000036 data = new unsigned char[bytes];
37 memset(data, 0, bytes);
38 dirty = true;
daniel@transgaming.com2d84df02010-05-14 17:31:13 +000039 handlesSet = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000040}
41
42Uniform::~Uniform()
43{
44 delete[] data;
45}
46
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +000047UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
48 : name(name), element(element), index(index)
49{
50}
51
daniel@transgaming.com73a5db62010-10-15 17:58:13 +000052Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000053{
54 mFragmentShader = NULL;
55 mVertexShader = NULL;
56
57 mPixelExecutable = NULL;
58 mVertexExecutable = NULL;
59 mConstantTablePS = NULL;
60 mConstantTableVS = NULL;
61
daniel@transgaming.comcba50572010-03-28 19:36:09 +000062 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +000063 mValidated = false;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000064
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000065 unlink();
66
67 mDeleteStatus = false;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000068
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000069 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000070}
71
72Program::~Program()
73{
74 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000075
76 if (mVertexShader != NULL)
77 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000078 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000079 }
80
81 if (mFragmentShader != NULL)
82 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000083 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000084 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000085}
86
87bool Program::attachShader(Shader *shader)
88{
89 if (shader->getType() == GL_VERTEX_SHADER)
90 {
91 if (mVertexShader)
92 {
93 return false;
94 }
95
96 mVertexShader = (VertexShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000097 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000098 }
99 else if (shader->getType() == GL_FRAGMENT_SHADER)
100 {
101 if (mFragmentShader)
102 {
103 return false;
104 }
105
106 mFragmentShader = (FragmentShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000107 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000108 }
109 else UNREACHABLE();
110
111 return true;
112}
113
114bool Program::detachShader(Shader *shader)
115{
116 if (shader->getType() == GL_VERTEX_SHADER)
117 {
118 if (mVertexShader != shader)
119 {
120 return false;
121 }
122
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000123 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000124 mVertexShader = NULL;
125 }
126 else if (shader->getType() == GL_FRAGMENT_SHADER)
127 {
128 if (mFragmentShader != shader)
129 {
130 return false;
131 }
132
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000133 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000134 mFragmentShader = NULL;
135 }
136 else UNREACHABLE();
137
138 unlink();
139
140 return true;
141}
142
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000143int Program::getAttachedShadersCount() const
144{
145 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
146}
147
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148IDirect3DPixelShader9 *Program::getPixelShader()
149{
150 return mPixelExecutable;
151}
152
153IDirect3DVertexShader9 *Program::getVertexShader()
154{
155 return mVertexExecutable;
156}
157
158void Program::bindAttributeLocation(GLuint index, const char *name)
159{
160 if (index < MAX_VERTEX_ATTRIBS)
161 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000162 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
163 {
164 mAttributeBinding[i].erase(name);
165 }
166
167 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000168 }
169}
170
171GLuint Program::getAttributeLocation(const char *name)
172{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000173 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000175 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000176 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000177 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000178 {
179 return index;
180 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000181 }
182 }
183
184 return -1;
185}
186
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000187int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000188{
daniel@transgaming.com733ba932011-04-14 15:03:48 +0000189 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
190
191 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000192}
193
194// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
195// index referenced in the compiled HLSL shader
196GLint Program::getSamplerMapping(unsigned int samplerIndex)
197{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000198 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
199
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000200 GLint logicalTextureUnit = -1;
201
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000202 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000203 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000204 logicalTextureUnit = mSamplers[samplerIndex].logicalTextureUnit;
205 }
206
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +0000207 if (logicalTextureUnit >= 0 && logicalTextureUnit < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000208 {
209 return logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210 }
211
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000212 return -1;
213}
214
215SamplerType Program::getSamplerType(unsigned int samplerIndex)
216{
217 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
218 assert(mSamplers[samplerIndex].active);
219
220 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000221}
222
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000223GLint Program::getUniformLocation(const char *name, bool decorated)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000224{
daniel@transgaming.comce864422010-11-18 13:16:49 +0000225 std::string _name = decorated ? name : decorate(name);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000226 int subscript = 0;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000227
daniel@transgaming.comce864422010-11-18 13:16:49 +0000228 // Strip any trailing array operator and retrieve the subscript
229 size_t open = _name.find_last_of('[');
230 size_t close = _name.find_last_of(']');
231 if (open != std::string::npos && close == _name.length() - 1)
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000232 {
daniel@transgaming.comce864422010-11-18 13:16:49 +0000233 subscript = atoi(_name.substr(open + 1).c_str());
234 _name.erase(open);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000235 }
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000236
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000237 unsigned int numUniforms = mUniformIndex.size();
238 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000239 {
daniel@transgaming.comce864422010-11-18 13:16:49 +0000240 if (mUniformIndex[location].name == _name &&
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000241 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000242 {
243 return location;
244 }
245 }
246
247 return -1;
248}
249
250bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
251{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000252 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000253 {
254 return false;
255 }
256
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000257 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000258 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000259
260 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000261 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000262 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000263
264 if (arraySize == 1 && count > 1)
265 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
266
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000267 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000268
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000269 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
270 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000271 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000272 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000273 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000274 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000275
276 if (arraySize == 1 && count > 1)
277 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000278
279 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000280 GLboolean *boolParams = new GLboolean[count];
281
282 for (int i = 0; i < count; ++i)
283 {
284 if (v[i] == 0.0f)
285 {
286 boolParams[i] = GL_FALSE;
287 }
288 else
289 {
290 boolParams[i] = GL_TRUE;
291 }
292 }
293
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000294 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
295 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000296
297 delete [] boolParams;
298 }
299 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000300 {
301 return false;
302 }
303
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000304 return true;
305}
306
307bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
308{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000309 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000310 {
311 return false;
312 }
313
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000314 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000315 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000316
317 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000318 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000319 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000320
321 if (arraySize == 1 && count > 1)
322 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
323
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000324 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000325
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000326 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
327 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000328 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000329 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000330 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000331 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000332
333 if (arraySize == 1 && count > 1)
334 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
335
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000336 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
337
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000338 GLboolean *boolParams = new GLboolean[count * 2];
339
340 for (int i = 0; i < count * 2; ++i)
341 {
342 if (v[i] == 0.0f)
343 {
344 boolParams[i] = GL_FALSE;
345 }
346 else
347 {
348 boolParams[i] = GL_TRUE;
349 }
350 }
351
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000352 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
353 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000354
355 delete [] boolParams;
356 }
357 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000358 {
359 return false;
360 }
361
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000362 return true;
363}
364
365bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
366{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000367 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000368 {
369 return false;
370 }
371
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000372 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000373 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000374
375 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000376 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000377 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000378
379 if (arraySize == 1 && count > 1)
380 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
381
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000382 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000383
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000384 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
385 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000386 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000387 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000388 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000389 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000390
391 if (arraySize == 1 && count > 1)
392 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
393
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000394 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000395 GLboolean *boolParams = new GLboolean[count * 3];
396
397 for (int i = 0; i < count * 3; ++i)
398 {
399 if (v[i] == 0.0f)
400 {
401 boolParams[i] = GL_FALSE;
402 }
403 else
404 {
405 boolParams[i] = GL_TRUE;
406 }
407 }
408
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000409 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
410 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000411
412 delete [] boolParams;
413 }
414 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000415 {
416 return false;
417 }
418
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000419 return true;
420}
421
422bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
423{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000424 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000425 {
426 return false;
427 }
428
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000429 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000430 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000431
432 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000433 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000434 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000435
436 if (arraySize == 1 && count > 1)
437 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
438
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000439 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000440
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000441 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
442 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000443 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000444 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000445 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000446 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000447
448 if (arraySize == 1 && count > 1)
449 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
450
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000451 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000452 GLboolean *boolParams = new GLboolean[count * 4];
453
454 for (int i = 0; i < count * 4; ++i)
455 {
456 if (v[i] == 0.0f)
457 {
458 boolParams[i] = GL_FALSE;
459 }
460 else
461 {
462 boolParams[i] = GL_TRUE;
463 }
464 }
465
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000466 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
467 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000468
469 delete [] boolParams;
470 }
471 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000472 {
473 return false;
474 }
475
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000476 return true;
477}
478
479bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
480{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000481 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000482 {
483 return false;
484 }
485
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000486 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000487 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000488
489 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000490 {
491 return false;
492 }
493
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000494 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000495
496 if (arraySize == 1 && count > 1)
497 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
498
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000499 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000500
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000501 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
502 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000503
504 return true;
505}
506
507bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
508{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000509 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000510 {
511 return false;
512 }
513
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000514 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000515 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000516
517 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000518 {
519 return false;
520 }
521
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000522 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000523
524 if (arraySize == 1 && count > 1)
525 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
526
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000527 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000528
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000529 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
530 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000531
532 return true;
533}
534
535bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
536{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000537 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000538 {
539 return false;
540 }
541
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000542 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000543 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000544
545 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000546 {
547 return false;
548 }
549
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000550 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000551
552 if (arraySize == 1 && count > 1)
553 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
554
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000555 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000556
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000557 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
558 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000559
560 return true;
561}
562
563bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
564{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000565 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000566 {
567 return false;
568 }
569
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000570 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000571 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000572
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000573 if (targetUniform->type == GL_INT ||
574 targetUniform->type == GL_SAMPLER_2D ||
575 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000576 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000577 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000578
579 if (arraySize == 1 && count > 1)
580 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
581
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000582 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000583
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000584 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
585 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000586 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000587 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000588 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000589 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000590
591 if (arraySize == 1 && count > 1)
592 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
593
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000594 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000595 GLboolean *boolParams = new GLboolean[count];
596
597 for (int i = 0; i < count; ++i)
598 {
599 if (v[i] == 0)
600 {
601 boolParams[i] = GL_FALSE;
602 }
603 else
604 {
605 boolParams[i] = GL_TRUE;
606 }
607 }
608
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000609 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
610 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000611
612 delete [] boolParams;
613 }
614 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000615 {
616 return false;
617 }
618
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000619 return true;
620}
621
622bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
623{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000624 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000625 {
626 return false;
627 }
628
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000629 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000630 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000631
632 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000633 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000634 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000635
636 if (arraySize == 1 && count > 1)
637 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
638
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000639 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000640
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000641 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
642 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000643 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000644 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000645 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000646 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000647
648 if (arraySize == 1 && count > 1)
649 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
650
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000651 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000652 GLboolean *boolParams = new GLboolean[count * 2];
653
654 for (int i = 0; i < count * 2; ++i)
655 {
656 if (v[i] == 0)
657 {
658 boolParams[i] = GL_FALSE;
659 }
660 else
661 {
662 boolParams[i] = GL_TRUE;
663 }
664 }
665
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000666 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
667 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000668
669 delete [] boolParams;
670 }
671 else
672 {
673 return false;
674 }
675
676 return true;
677}
678
679bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
680{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000681 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000682 {
683 return false;
684 }
685
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000686 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000687 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000688
689 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000690 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000691 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000692
693 if (arraySize == 1 && count > 1)
694 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
695
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000696 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000697
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000698 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
699 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000700 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000701 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000702 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000703 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000704
705 if (arraySize == 1 && count > 1)
706 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
707
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000708 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000709 GLboolean *boolParams = new GLboolean[count * 3];
710
711 for (int i = 0; i < count * 3; ++i)
712 {
713 if (v[i] == 0)
714 {
715 boolParams[i] = GL_FALSE;
716 }
717 else
718 {
719 boolParams[i] = GL_TRUE;
720 }
721 }
722
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000723 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
724 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000725
726 delete [] boolParams;
727 }
728 else
729 {
730 return false;
731 }
732
733 return true;
734}
735
736bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
737{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000738 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000739 {
740 return false;
741 }
742
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000743 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000744 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000745
746 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000747 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000748 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000749
750 if (arraySize == 1 && count > 1)
751 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
752
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000753 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000754
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000755 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
756 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000757 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000758 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000759 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000760 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000761
762 if (arraySize == 1 && count > 1)
763 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
764
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000765 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000766 GLboolean *boolParams = new GLboolean[count * 4];
767
768 for (int i = 0; i < count * 4; ++i)
769 {
770 if (v[i] == 0)
771 {
772 boolParams[i] = GL_FALSE;
773 }
774 else
775 {
776 boolParams[i] = GL_TRUE;
777 }
778 }
779
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000780 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
781 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000782
783 delete [] boolParams;
784 }
785 else
786 {
787 return false;
788 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000789
790 return true;
791}
792
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000793bool Program::getUniformfv(GLint location, GLfloat *params)
794{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000795 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000796 {
797 return false;
798 }
799
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000800 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000801
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000802 unsigned int count = UniformComponentCount(targetUniform->type);
803
804 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000805 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000806 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000807 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000808 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000809
810 for (unsigned int i = 0; i < count; ++i)
811 {
812 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
813 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000814 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000815 break;
816 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000817 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
818 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000819 break;
820 case GL_INT:
821 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000822 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000823
824 for (unsigned int i = 0; i < count; ++i)
825 {
826 params[i] = (float)intParams[i];
827 }
828 }
829 break;
830 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000831 }
832
833 return true;
834}
835
836bool Program::getUniformiv(GLint location, GLint *params)
837{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000838 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000839 {
840 return false;
841 }
842
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000843 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000844
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000845 unsigned int count = UniformComponentCount(targetUniform->type);
846
847 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000848 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000849 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000850 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000851 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000852
853 for (unsigned int i = 0; i < count; ++i)
854 {
855 params[i] = (GLint)boolParams[i];
856 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000857 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000858 break;
859 case GL_FLOAT:
860 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000861 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000862
863 for (unsigned int i = 0; i < count; ++i)
864 {
865 params[i] = (GLint)floatParams[i];
866 }
867 }
868 break;
869 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000870 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
871 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000872 break;
873 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000874 }
875
876 return true;
877}
878
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000879void Program::dirtyAllUniforms()
880{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000881 unsigned int numUniforms = mUniforms.size();
882 for (unsigned int index = 0; index < numUniforms; index++)
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000883 {
884 mUniforms[index]->dirty = true;
885 }
886}
887
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000888// Applies all the uniforms set for this program object to the Direct3D 9 device
889void Program::applyUniforms()
890{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000891 unsigned int numUniforms = mUniformIndex.size();
892 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000893 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000894 if (mUniformIndex[location].element != 0)
895 {
896 continue;
897 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000898
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000899 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
900
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000901 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000902 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000903 int arraySize = targetUniform->arraySize;
904 GLfloat *f = (GLfloat*)targetUniform->data;
905 GLint *i = (GLint*)targetUniform->data;
906 GLboolean *b = (GLboolean*)targetUniform->data;
907
908 switch (targetUniform->type)
909 {
910 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
911 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
912 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
913 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
914 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
915 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
916 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
917 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
918 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
919 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
920 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000921 case GL_SAMPLER_2D:
922 case GL_SAMPLER_CUBE:
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000923 case GL_INT: applyUniform1iv(location, arraySize, i); break;
924 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
925 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
926 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
927 default:
928 UNREACHABLE();
929 }
930
931 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000932 }
933 }
934}
935
936// Compiles the HLSL code of the attached shaders into executable binaries
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000937ID3D10Blob *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000938{
939 if (!hlsl)
940 {
941 return NULL;
942 }
943
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000944 DWORD result;
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000945 UINT flags = 0;
946 std::string sourceText;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000947 if (perfActive())
948 {
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000949 flags |= D3DCOMPILE_DEBUG;
950#ifdef NDEBUG
951 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
952#else
953 flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000954#endif
955
956 std::string sourcePath = getTempPath();
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000957 sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000958 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000959 }
960 else
961 {
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000962 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
963 sourceText = hlsl;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000964 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000965
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000966 ID3D10Blob *binary = NULL;
967 ID3D10Blob *errorMessage = NULL;
968 result = D3DCompile(hlsl, strlen(hlsl), NULL, NULL, NULL, "main", profile, flags, 0, &binary, &errorMessage);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000969
970 if (errorMessage)
971 {
972 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000973
daniel@transgaming.com0df16872010-05-12 16:51:08 +0000974 appendToInfoLog("%s\n", message);
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000975 TRACE("\n%s", hlsl);
976 TRACE("\n%s", message);
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000977
978 errorMessage->Release();
979 errorMessage = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000980 }
981
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000982
983 if (FAILED(result))
984 {
985 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
986 {
987 error(GL_OUT_OF_MEMORY);
988 }
989
990 return NULL;
991 }
992
993 result = D3DXGetShaderConstantTable(static_cast<const DWORD*>(binary->GetBufferPointer()), constantTable);
994
995 if (FAILED(result))
996 {
997 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
998 {
999 error(GL_OUT_OF_MEMORY);
1000 }
1001
1002 binary->Release();
1003
1004 return NULL;
1005 }
1006
1007 return binary;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001008}
1009
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001010// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1011// Returns the number of used varying registers, or -1 if unsuccesful
1012int Program::packVaryings(const Varying *packing[][4])
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001013{
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001014 Context *context = getContext();
1015 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1016
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001017 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001018 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001019 int n = VariableRowCount(varying->type) * varying->size;
1020 int m = VariableColumnCount(varying->type);
1021 bool success = false;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001022
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001023 if (m == 2 || m == 3 || m == 4)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001024 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001025 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001026 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001027 bool available = true;
1028
1029 for (int y = 0; y < n && available; y++)
1030 {
1031 for (int x = 0; x < m && available; x++)
1032 {
1033 if (packing[r + y][x])
1034 {
1035 available = false;
1036 }
1037 }
1038 }
1039
1040 if (available)
1041 {
1042 varying->reg = r;
1043 varying->col = 0;
1044
1045 for (int y = 0; y < n; y++)
1046 {
1047 for (int x = 0; x < m; x++)
1048 {
1049 packing[r + y][x] = &*varying;
1050 }
1051 }
1052
1053 success = true;
1054 }
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001055 }
1056
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001057 if (!success && m == 2)
1058 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001059 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001060 {
1061 bool available = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001062
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001063 for (int y = 0; y < n && available; y++)
1064 {
1065 for (int x = 2; x < 4 && available; x++)
1066 {
1067 if (packing[r + y][x])
1068 {
1069 available = false;
1070 }
1071 }
1072 }
1073
1074 if (available)
1075 {
1076 varying->reg = r;
1077 varying->col = 2;
1078
1079 for (int y = 0; y < n; y++)
1080 {
1081 for (int x = 2; x < 4; x++)
1082 {
1083 packing[r + y][x] = &*varying;
1084 }
1085 }
1086
1087 success = true;
1088 }
1089 }
1090 }
1091 }
1092 else if (m == 1)
1093 {
1094 int space[4] = {0};
1095
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001096 for (int y = 0; y < maxVaryingVectors; y++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001097 {
1098 for (int x = 0; x < 4; x++)
1099 {
1100 space[x] += packing[y][x] ? 0 : 1;
1101 }
1102 }
1103
1104 int column = 0;
1105
1106 for (int x = 0; x < 4; x++)
1107 {
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001108 if (space[x] >= n && space[x] < space[column])
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001109 {
1110 column = x;
1111 }
1112 }
1113
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001114 if (space[column] >= n)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001115 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001116 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001117 {
1118 if (!packing[r][column])
1119 {
1120 varying->reg = r;
1121
1122 for (int y = r; y < r + n; y++)
1123 {
1124 packing[y][column] = &*varying;
1125 }
1126
1127 break;
1128 }
1129 }
1130
1131 varying->col = column;
1132
1133 success = true;
1134 }
1135 }
1136 else UNREACHABLE();
1137
1138 if (!success)
1139 {
1140 appendToInfoLog("Could not pack varying %s", varying->name.c_str());
1141
1142 return -1;
1143 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001144 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001145
1146 // Return the number of used registers
1147 int registers = 0;
1148
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001149 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001150 {
1151 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1152 {
1153 registers++;
1154 }
1155 }
1156
1157 return registers;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001158}
1159
1160bool Program::linkVaryings()
1161{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001162 if (mPixelHLSL.empty() || mVertexHLSL.empty())
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001163 {
1164 return false;
1165 }
1166
daniel@transgaming.com97750022011-02-11 13:23:13 +00001167 // Reset the varying register assignments
1168 for (VaryingList::iterator fragVar = mFragmentShader->varyings.begin(); fragVar != mFragmentShader->varyings.end(); fragVar++)
1169 {
1170 fragVar->reg = -1;
1171 fragVar->col = -1;
1172 }
1173
1174 for (VaryingList::iterator vtxVar = mVertexShader->varyings.begin(); vtxVar != mVertexShader->varyings.end(); vtxVar++)
1175 {
1176 vtxVar->reg = -1;
1177 vtxVar->col = -1;
1178 }
1179
1180 // Map the varyings to the register file
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001181 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001182 int registers = packVaryings(packing);
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001183
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001184 if (registers < 0)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001185 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001186 return false;
1187 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001188
daniel@transgaming.com97750022011-02-11 13:23:13 +00001189 // Write the HLSL input/output declarations
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001190 Context *context = getContext();
1191 const bool sm3 = context->supportsShaderModel3();
1192 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1193
1194 if (registers == maxVaryingVectors && mFragmentShader->mUsesFragCoord)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001195 {
1196 appendToInfoLog("No varying registers left to support gl_FragCoord");
1197
1198 return false;
1199 }
1200
1201 for (VaryingList::iterator input = mFragmentShader->varyings.begin(); input != mFragmentShader->varyings.end(); input++)
1202 {
1203 bool matched = false;
1204
1205 for (VaryingList::iterator output = mVertexShader->varyings.begin(); output != mVertexShader->varyings.end(); output++)
1206 {
1207 if (output->name == input->name)
1208 {
1209 if (output->type != input->type || output->size != input->size)
1210 {
1211 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
1212
1213 return false;
1214 }
1215
1216 output->reg = input->reg;
1217 output->col = input->col;
1218
1219 matched = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001220 break;
1221 }
1222 }
1223
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001224 if (!matched)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001225 {
daniel@transgaming.com97750022011-02-11 13:23:13 +00001226 appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001227
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001228 return false;
1229 }
1230 }
1231
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001232 std::string varyingSemantic = (sm3 ? "COLOR" : "TEXCOORD");
1233
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001234 mVertexHLSL += "struct VS_INPUT\n"
1235 "{\n";
1236
1237 int semanticIndex = 0;
1238 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1239 {
1240 switch (attribute->type)
1241 {
1242 case GL_FLOAT: mVertexHLSL += " float "; break;
1243 case GL_FLOAT_VEC2: mVertexHLSL += " float2 "; break;
1244 case GL_FLOAT_VEC3: mVertexHLSL += " float3 "; break;
1245 case GL_FLOAT_VEC4: mVertexHLSL += " float4 "; break;
1246 case GL_FLOAT_MAT2: mVertexHLSL += " float2x2 "; break;
1247 case GL_FLOAT_MAT3: mVertexHLSL += " float3x3 "; break;
1248 case GL_FLOAT_MAT4: mVertexHLSL += " float4x4 "; break;
1249 default: UNREACHABLE();
1250 }
1251
1252 mVertexHLSL += decorate(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1253
1254 semanticIndex += VariableRowCount(attribute->type);
1255 }
1256
1257 mVertexHLSL += "};\n"
1258 "\n"
1259 "struct VS_OUTPUT\n"
1260 "{\n"
1261 " float4 gl_Position : POSITION;\n";
1262
1263 for (int r = 0; r < registers; r++)
1264 {
1265 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1266
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001267 mVertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001268 }
1269
1270 if (mFragmentShader->mUsesFragCoord)
1271 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001272 mVertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1273 }
1274
1275 if (mVertexShader->mUsesPointSize && sm3)
1276 {
1277 mVertexHLSL += " float gl_PointSize : PSIZE;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001278 }
1279
1280 mVertexHLSL += "};\n"
1281 "\n"
1282 "VS_OUTPUT main(VS_INPUT input)\n"
1283 "{\n";
1284
1285 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1286 {
1287 mVertexHLSL += " " + decorate(attribute->name) + " = ";
1288
1289 if (VariableRowCount(attribute->type) > 1) // Matrix
1290 {
1291 mVertexHLSL += "transpose";
1292 }
1293
1294 mVertexHLSL += "(input." + decorate(attribute->name) + ");\n";
1295 }
1296
1297 mVertexHLSL += "\n"
1298 " gl_main();\n"
1299 "\n"
1300 " VS_OUTPUT output;\n"
1301 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001302 " output.gl_Position.y = gl_Position.y - dx_HalfPixelSize.y * gl_Position.w;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001303 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1304 " output.gl_Position.w = gl_Position.w;\n";
1305
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001306 if (mVertexShader->mUsesPointSize && sm3)
1307 {
1308 mVertexHLSL += " output.gl_PointSize = clamp(gl_PointSize, 1.0, " + str((int)ALIASED_POINT_SIZE_RANGE_MAX_SM3) + ");\n";
1309 }
1310
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001311 if (mFragmentShader->mUsesFragCoord)
1312 {
1313 mVertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1314 }
1315
1316 for (VaryingList::iterator varying = mVertexShader->varyings.begin(); varying != mVertexShader->varyings.end(); varying++)
1317 {
1318 if (varying->reg >= 0)
1319 {
1320 for (int i = 0; i < varying->size; i++)
1321 {
1322 int rows = VariableRowCount(varying->type);
1323
1324 for (int j = 0; j < rows; j++)
1325 {
1326 int r = varying->reg + i * rows + j;
1327 mVertexHLSL += " output.v" + str(r);
1328
1329 bool sharedRegister = false; // Register used by multiple varyings
1330
1331 for (int x = 0; x < 4; x++)
1332 {
1333 if (packing[r][x] && packing[r][x] != packing[r][0])
1334 {
1335 sharedRegister = true;
1336 break;
1337 }
1338 }
1339
1340 if(sharedRegister)
1341 {
1342 mVertexHLSL += ".";
1343
1344 for (int x = 0; x < 4; x++)
1345 {
1346 if (packing[r][x] == &*varying)
1347 {
1348 switch(x)
1349 {
1350 case 0: mVertexHLSL += "x"; break;
1351 case 1: mVertexHLSL += "y"; break;
1352 case 2: mVertexHLSL += "z"; break;
1353 case 3: mVertexHLSL += "w"; break;
1354 }
1355 }
1356 }
1357 }
1358
1359 mVertexHLSL += " = " + varying->name;
1360
1361 if (varying->array)
1362 {
1363 mVertexHLSL += "[" + str(i) + "]";
1364 }
1365
1366 if (rows > 1)
1367 {
1368 mVertexHLSL += "[" + str(j) + "]";
1369 }
1370
1371 mVertexHLSL += ";\n";
1372 }
1373 }
1374 }
1375 }
1376
1377 mVertexHLSL += "\n"
1378 " return output;\n"
1379 "}\n";
1380
1381 mPixelHLSL += "struct PS_INPUT\n"
1382 "{\n";
1383
1384 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1385 {
1386 if (varying->reg >= 0)
1387 {
1388 for (int i = 0; i < varying->size; i++)
1389 {
1390 int rows = VariableRowCount(varying->type);
1391 for (int j = 0; j < rows; j++)
1392 {
1393 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001394 mPixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001395 }
1396 }
1397 }
1398 else UNREACHABLE();
1399 }
1400
1401 if (mFragmentShader->mUsesFragCoord)
1402 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001403 mPixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001404 if (sm3) {
daniel@transgaming.com996675c2010-11-17 13:06:29 +00001405 mPixelHLSL += " float2 dx_VPos : VPOS;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001406 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001407 }
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001408
1409 if (mFragmentShader->mUsesPointCoord && sm3)
1410 {
1411 mPixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1412 }
1413
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001414 if (mFragmentShader->mUsesFrontFacing)
1415 {
1416 mPixelHLSL += " float vFace : VFACE;\n";
1417 }
1418
1419 mPixelHLSL += "};\n"
1420 "\n"
1421 "struct PS_OUTPUT\n"
1422 "{\n"
1423 " float4 gl_Color[1] : COLOR;\n"
1424 "};\n"
1425 "\n"
1426 "PS_OUTPUT main(PS_INPUT input)\n"
1427 "{\n";
1428
1429 if (mFragmentShader->mUsesFragCoord)
1430 {
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001431 mPixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1432 if (sm3) {
1433 mPixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001434 " gl_FragCoord.y = 2.0 * dx_Viewport.y - input.dx_VPos.y;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001435 } else {
1436 mPixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Viewport.x + dx_Viewport.z;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001437 " gl_FragCoord.y = -(input.gl_FragCoord.y * rhw) * dx_Viewport.y + dx_Viewport.w;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001438 }
1439 mPixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001440 " gl_FragCoord.w = rhw;\n";
1441 }
1442
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001443 if (mFragmentShader->mUsesPointCoord && sm3)
1444 {
apatrick@chromium.orgda4d0492011-01-22 00:16:10 +00001445 mPixelHLSL += " gl_PointCoord = input.gl_PointCoord;\n";
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001446 }
1447
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001448 if (mFragmentShader->mUsesFrontFacing)
1449 {
1450 mPixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1451 }
1452
1453 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1454 {
1455 if (varying->reg >= 0)
1456 {
1457 for (int i = 0; i < varying->size; i++)
1458 {
1459 int rows = VariableRowCount(varying->type);
1460 for (int j = 0; j < rows; j++)
1461 {
1462 std::string n = str(varying->reg + i * rows + j);
1463 mPixelHLSL += " " + varying->name;
1464
1465 if (varying->array)
1466 {
1467 mPixelHLSL += "[" + str(i) + "]";
1468 }
1469
1470 if (rows > 1)
1471 {
1472 mPixelHLSL += "[" + str(j) + "]";
1473 }
1474
1475 mPixelHLSL += " = input.v" + n + ";\n";
1476 }
1477 }
1478 }
1479 else UNREACHABLE();
1480 }
1481
1482 mPixelHLSL += "\n"
1483 " gl_main();\n"
1484 "\n"
1485 " PS_OUTPUT output;\n"
1486 " output.gl_Color[0] = gl_Color[0];\n"
1487 "\n"
1488 " return output;\n"
1489 "}\n";
1490
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001491 return true;
1492}
1493
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001494// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1495// compiling them into binaries, determining the attribute mappings, and collecting
1496// a list of uniforms
1497void Program::link()
1498{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001499 unlink();
1500
1501 if (!mFragmentShader || !mFragmentShader->isCompiled())
1502 {
1503 return;
1504 }
1505
1506 if (!mVertexShader || !mVertexShader->isCompiled())
1507 {
1508 return;
1509 }
1510
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001511 mPixelHLSL = mFragmentShader->getHLSL();
1512 mVertexHLSL = mVertexShader->getHLSL();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001513
1514 if (!linkVaryings())
1515 {
1516 return;
1517 }
1518
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001519 Context *context = getContext();
1520 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1521 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1522
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001523 ID3D10Blob *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1524 ID3D10Blob *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001525
1526 if (vertexBinary && pixelBinary)
1527 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001528 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001529 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1530 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1531
1532 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1533 {
1534 return error(GL_OUT_OF_MEMORY);
1535 }
1536
1537 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001538
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001539 vertexBinary->Release();
1540 pixelBinary->Release();
1541 vertexBinary = NULL;
1542 pixelBinary = NULL;
1543
1544 if (mVertexExecutable && mPixelExecutable)
1545 {
1546 if (!linkAttributes())
1547 {
1548 return;
1549 }
1550
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001551 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001552 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001553 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001554 }
1555
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001556 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001557 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001558 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001559 }
1560
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001561 // these uniforms are searched as already-decorated because gl_ and dx_
1562 // are reserved prefixes, and do not receive additional decoration
daniel@transgaming.com31754962010-11-28 02:02:52 +00001563 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange", true);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001564 mDxDepthLocation = getUniformLocation("dx_Depth", true);
daniel@transgaming.com162267d2010-07-28 19:20:48 +00001565 mDxViewportLocation = getUniformLocation("dx_Viewport", true);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001566 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize", true);
1567 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW", true);
1568 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines", true);
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00001569
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001570 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001571 }
1572 }
1573}
1574
1575// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1576bool Program::linkAttributes()
1577{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001578 unsigned int usedLocations = 0;
1579
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001580 // Link attributes that have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001581 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001582 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001583 int location = getAttributeBinding(attribute->name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001584
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001585 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001586 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001587 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001588 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001589 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001590 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001591
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001592 mLinkedAttribute[location] = *attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001593
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001594 int rows = VariableRowCount(attribute->type);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001595
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001596 if (rows + location > MAX_VERTEX_ATTRIBS)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001597 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001598 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 +00001599
1600 return false;
1601 }
1602
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001603 for (int i = 0; i < rows; i++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001604 {
1605 usedLocations |= 1 << (location + i);
1606 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001607 }
1608 }
1609
1610 // Link attributes that don't have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001611 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001612 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001613 int location = getAttributeBinding(attribute->name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001614
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001615 if (location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001616 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001617 int rows = VariableRowCount(attribute->type);
1618 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001619
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001620 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001621 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001622 appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001623
1624 return false; // Fail to link
1625 }
1626
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001627 mLinkedAttribute[availableIndex] = *attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001628 }
1629 }
1630
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001631 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001632 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001633 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001634 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001635
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001636 for (int r = 0; r < rows; r++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001637 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001638 mSemanticIndex[attributeIndex++] = index++;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001639 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001640 }
1641
1642 return true;
1643}
1644
daniel@transgaming.com85423182010-04-22 13:35:27 +00001645int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001646{
1647 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1648 {
1649 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1650 {
1651 return location;
1652 }
1653 }
1654
1655 return -1;
1656}
1657
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001658bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1659{
1660 D3DXCONSTANTTABLE_DESC constantTableDescription;
1661 D3DXCONSTANT_DESC constantDescription;
1662 UINT descriptionCount = 1;
1663
1664 constantTable->GetDesc(&constantTableDescription);
1665
1666 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1667 {
1668 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1669 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1670
1671 if (!defineUniform(constantHandle, constantDescription))
1672 {
1673 return false;
1674 }
1675 }
1676
1677 return true;
1678}
1679
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001680// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001681// Returns true if succesful (uniform not already defined)
1682bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1683{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001684 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1685 {
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001686 for (unsigned int samplerIndex = constantDescription.RegisterIndex; samplerIndex < constantDescription.RegisterIndex + constantDescription.RegisterCount; samplerIndex++)
1687 {
1688 ASSERT(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001689
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001690 mSamplers[samplerIndex].active = true;
1691 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1692 mSamplers[samplerIndex].logicalTextureUnit = 0;
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001693 }
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001694 }
1695
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001696 switch(constantDescription.Class)
1697 {
1698 case D3DXPC_STRUCT:
1699 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001700 for (unsigned int arrayIndex = 0; arrayIndex < constantDescription.Elements; arrayIndex++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001701 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001702 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001703 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001704 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1705
1706 D3DXCONSTANT_DESC fieldDescription;
1707 UINT descriptionCount = 1;
1708
1709 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1710
1711 std::string structIndex = (constantDescription.Elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
1712
1713 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + structIndex + "."))
1714 {
1715 return false;
1716 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001717 }
1718 }
1719
1720 return true;
1721 }
1722 case D3DXPC_SCALAR:
1723 case D3DXPC_VECTOR:
1724 case D3DXPC_MATRIX_COLUMNS:
1725 case D3DXPC_OBJECT:
1726 return defineUniform(constantDescription, name + constantDescription.Name);
1727 default:
1728 UNREACHABLE();
1729 return false;
1730 }
1731}
1732
1733bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1734{
1735 Uniform *uniform = createUniform(constantDescription, name);
1736
1737 if(!uniform)
1738 {
1739 return false;
1740 }
1741
1742 // Check if already defined
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001743 GLint location = getUniformLocation(name.c_str(), true);
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001744 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001745
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001746 if (location >= 0)
1747 {
1748 delete uniform;
1749
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001750 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001751 {
1752 return false;
1753 }
1754 else
1755 {
1756 return true;
1757 }
1758 }
1759
1760 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001761 unsigned int uniformIndex = mUniforms.size() - 1;
1762
1763 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1764 {
1765 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1766 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001767
1768 return true;
1769}
1770
1771Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001772{
1773 if (constantDescription.Rows == 1) // Vectors and scalars
1774 {
1775 switch (constantDescription.Type)
1776 {
1777 case D3DXPT_SAMPLER2D:
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001778 switch (constantDescription.Columns)
1779 {
1780 case 1: return new Uniform(GL_SAMPLER_2D, name, constantDescription.Elements);
1781 default: UNREACHABLE();
1782 }
1783 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001784 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001785 switch (constantDescription.Columns)
1786 {
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001787 case 1: return new Uniform(GL_SAMPLER_CUBE, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001788 default: UNREACHABLE();
1789 }
1790 break;
1791 case D3DXPT_BOOL:
1792 switch (constantDescription.Columns)
1793 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001794 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1795 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1796 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1797 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001798 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001799 }
1800 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001801 case D3DXPT_INT:
1802 switch (constantDescription.Columns)
1803 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001804 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1805 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1806 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1807 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001808 default: UNREACHABLE();
1809 }
1810 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001811 case D3DXPT_FLOAT:
1812 switch (constantDescription.Columns)
1813 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001814 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1815 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1816 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1817 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001818 default: UNREACHABLE();
1819 }
1820 break;
1821 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001822 UNREACHABLE();
1823 }
1824 }
1825 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1826 {
1827 switch (constantDescription.Type)
1828 {
1829 case D3DXPT_FLOAT:
1830 switch (constantDescription.Rows)
1831 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001832 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1833 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1834 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001835 default: UNREACHABLE();
1836 }
1837 break;
1838 default: UNREACHABLE();
1839 }
1840 }
1841 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001842
1843 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001844}
1845
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001846// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001847std::string Program::decorate(const std::string &string)
1848{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001849 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001850 {
1851 return "_" + string;
1852 }
1853 else
1854 {
1855 return string;
1856 }
1857}
1858
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001859std::string Program::undecorate(const std::string &string)
1860{
1861 if (string.substr(0, 1) == "_")
1862 {
1863 return string.substr(1);
1864 }
1865 else
1866 {
1867 return string;
1868 }
1869}
1870
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001871bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1872{
1873 BOOL *vector = new BOOL[count];
1874 for (int i = 0; i < count; i++)
1875 {
1876 if (v[i] == GL_FALSE)
1877 vector[i] = 0;
1878 else
1879 vector[i] = 1;
1880 }
1881
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001882 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1883
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001884 D3DXHANDLE constantPS;
1885 D3DXHANDLE constantVS;
1886 getConstantHandles(targetUniform, &constantPS, &constantVS);
1887
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001888 IDirect3DDevice9 *device = getDevice();
1889
1890 if (constantPS)
1891 {
1892 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1893 }
1894
1895 if (constantVS)
1896 {
1897 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1898 }
1899
1900 delete [] vector;
1901
1902 return true;
1903}
1904
1905bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1906{
1907 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1908
1909 for (int i = 0; i < count; i++)
1910 {
1911 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1912 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1913
1914 v += 2;
1915 }
1916
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001917 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1918
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001919 D3DXHANDLE constantPS;
1920 D3DXHANDLE constantVS;
1921 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001922 IDirect3DDevice9 *device = getDevice();
1923
1924 if (constantPS)
1925 {
1926 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1927 }
1928
1929 if (constantVS)
1930 {
1931 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1932 }
1933
1934 delete[] vector;
1935
1936 return true;
1937}
1938
1939bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1940{
1941 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1942
1943 for (int i = 0; i < count; i++)
1944 {
1945 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1946 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1947 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1948
1949 v += 3;
1950 }
1951
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001952 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1953
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001954 D3DXHANDLE constantPS;
1955 D3DXHANDLE constantVS;
1956 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001957 IDirect3DDevice9 *device = getDevice();
1958
1959 if (constantPS)
1960 {
1961 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1962 }
1963
1964 if (constantVS)
1965 {
1966 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1967 }
1968
1969 delete[] vector;
1970
1971 return true;
1972}
1973
1974bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1975{
1976 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1977
1978 for (int i = 0; i < count; i++)
1979 {
1980 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1981 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1982 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1983 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1984
1985 v += 3;
1986 }
1987
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001988 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1989
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001990 D3DXHANDLE constantPS;
1991 D3DXHANDLE constantVS;
1992 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001993 IDirect3DDevice9 *device = getDevice();
1994
1995 if (constantPS)
1996 {
1997 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1998 }
1999
2000 if (constantVS)
2001 {
2002 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2003 }
2004
2005 delete [] vector;
2006
2007 return true;
2008}
2009
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002010bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
2011{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002012 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2013
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002014 D3DXHANDLE constantPS;
2015 D3DXHANDLE constantVS;
2016 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002017 IDirect3DDevice9 *device = getDevice();
2018
2019 if (constantPS)
2020 {
2021 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
2022 }
2023
2024 if (constantVS)
2025 {
2026 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
2027 }
2028
2029 return true;
2030}
2031
2032bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
2033{
2034 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2035
2036 for (int i = 0; i < count; i++)
2037 {
2038 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
2039
2040 v += 2;
2041 }
2042
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002043 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2044
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002045 D3DXHANDLE constantPS;
2046 D3DXHANDLE constantVS;
2047 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002048 IDirect3DDevice9 *device = getDevice();
2049
2050 if (constantPS)
2051 {
2052 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2053 }
2054
2055 if (constantVS)
2056 {
2057 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2058 }
2059
2060 delete[] vector;
2061
2062 return true;
2063}
2064
2065bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
2066{
2067 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2068
2069 for (int i = 0; i < count; i++)
2070 {
2071 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
2072
2073 v += 3;
2074 }
2075
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002076 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2077
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002078 D3DXHANDLE constantPS;
2079 D3DXHANDLE constantVS;
2080 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002081 IDirect3DDevice9 *device = getDevice();
2082
2083 if (constantPS)
2084 {
2085 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2086 }
2087
2088 if (constantVS)
2089 {
2090 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2091 }
2092
2093 delete[] vector;
2094
2095 return true;
2096}
2097
2098bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
2099{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002100 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2101
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002102 D3DXHANDLE constantPS;
2103 D3DXHANDLE constantVS;
2104 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002105 IDirect3DDevice9 *device = getDevice();
2106
2107 if (constantPS)
2108 {
2109 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
2110 }
2111
2112 if (constantVS)
2113 {
2114 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
2115 }
2116
2117 return true;
2118}
2119
2120bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
2121{
2122 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2123
2124 for (int i = 0; i < count; i++)
2125 {
2126 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
2127 value[1], value[3], 0, 0,
2128 0, 0, 1, 0,
2129 0, 0, 0, 1);
2130
2131 value += 4;
2132 }
2133
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002134 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2135
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002136 D3DXHANDLE constantPS;
2137 D3DXHANDLE constantVS;
2138 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002139 IDirect3DDevice9 *device = getDevice();
2140
2141 if (constantPS)
2142 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002143 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002144 }
2145
2146 if (constantVS)
2147 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002148 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002149 }
2150
2151 delete[] matrix;
2152
2153 return true;
2154}
2155
2156bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
2157{
2158 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2159
2160 for (int i = 0; i < count; i++)
2161 {
2162 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
2163 value[1], value[4], value[7], 0,
2164 value[2], value[5], value[8], 0,
2165 0, 0, 0, 1);
2166
2167 value += 9;
2168 }
2169
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002170 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2171
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002172 D3DXHANDLE constantPS;
2173 D3DXHANDLE constantVS;
2174 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002175 IDirect3DDevice9 *device = getDevice();
2176
2177 if (constantPS)
2178 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002179 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002180 }
2181
2182 if (constantVS)
2183 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002184 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002185 }
2186
2187 delete[] matrix;
2188
2189 return true;
2190}
2191
2192bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
2193{
2194 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2195
2196 for (int i = 0; i < count; i++)
2197 {
2198 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
2199 value[1], value[5], value[9], value[13],
2200 value[2], value[6], value[10], value[14],
2201 value[3], value[7], value[11], value[15]);
2202
2203 value += 16;
2204 }
2205
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002206 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2207
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002208 D3DXHANDLE constantPS;
2209 D3DXHANDLE constantVS;
2210 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002211 IDirect3DDevice9 *device = getDevice();
2212
2213 if (constantPS)
2214 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002215 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002216 }
2217
2218 if (constantVS)
2219 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002220 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002221 }
2222
2223 delete[] matrix;
2224
2225 return true;
2226}
2227
2228bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
2229{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002230 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2231
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002232 D3DXHANDLE constantPS;
2233 D3DXHANDLE constantVS;
2234 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002235 IDirect3DDevice9 *device = getDevice();
2236
2237 if (constantPS)
2238 {
2239 D3DXCONSTANT_DESC constantDescription;
2240 UINT descriptionCount = 1;
2241 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
2242
daniel@transgaming.com2884b782010-03-08 21:30:48 +00002243 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002244 {
2245 return false;
2246 }
2247
2248 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2249 {
2250 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
2251
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002252 for (int i = 0; i < count; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002253 {
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002254 unsigned int samplerIndex = firstIndex + i;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002255
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002256 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002257 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002258 ASSERT(mSamplers[samplerIndex].active);
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002259 mSamplers[samplerIndex].logicalTextureUnit = v[i];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002260 }
2261 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002262
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002263 return true;
2264 }
2265 }
2266
2267 if (constantPS)
2268 {
2269 mConstantTablePS->SetIntArray(device, constantPS, v, count);
2270 }
2271
2272 if (constantVS)
2273 {
2274 mConstantTableVS->SetIntArray(device, constantVS, v, count);
2275 }
2276
2277 return true;
2278}
2279
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002280bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
2281{
2282 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2283
2284 for (int i = 0; i < count; i++)
2285 {
2286 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2287
2288 v += 2;
2289 }
2290
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002291 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2292
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002293 D3DXHANDLE constantPS;
2294 D3DXHANDLE constantVS;
2295 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002296 IDirect3DDevice9 *device = getDevice();
2297
2298 if (constantPS)
2299 {
2300 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2301 }
2302
2303 if (constantVS)
2304 {
2305 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2306 }
2307
2308 delete[] vector;
2309
2310 return true;
2311}
2312
2313bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
2314{
2315 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2316
2317 for (int i = 0; i < count; i++)
2318 {
2319 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2320
2321 v += 3;
2322 }
2323
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002324 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2325
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002326 D3DXHANDLE constantPS;
2327 D3DXHANDLE constantVS;
2328 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002329 IDirect3DDevice9 *device = getDevice();
2330
2331 if (constantPS)
2332 {
2333 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2334 }
2335
2336 if (constantVS)
2337 {
2338 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2339 }
2340
2341 delete[] vector;
2342
2343 return true;
2344}
2345
2346bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
2347{
2348 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2349
2350 for (int i = 0; i < count; i++)
2351 {
2352 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2353
2354 v += 4;
2355 }
2356
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002357 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2358
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002359 D3DXHANDLE constantPS;
2360 D3DXHANDLE constantVS;
2361 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002362 IDirect3DDevice9 *device = getDevice();
2363
2364 if (constantPS)
2365 {
2366 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2367 }
2368
2369 if (constantVS)
2370 {
2371 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2372 }
2373
2374 delete [] vector;
2375
2376 return true;
2377}
2378
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002379void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002380{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002381 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002382 {
2383 return;
2384 }
2385
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002386 char info[1024];
2387
2388 va_list vararg;
2389 va_start(vararg, format);
2390 vsnprintf(info, sizeof(info), format, vararg);
2391 va_end(vararg);
2392
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002393 size_t infoLength = strlen(info);
2394
2395 if (!mInfoLog)
2396 {
2397 mInfoLog = new char[infoLength + 1];
2398 strcpy(mInfoLog, info);
2399 }
2400 else
2401 {
2402 size_t logLength = strlen(mInfoLog);
2403 char *newLog = new char[logLength + infoLength + 1];
2404 strcpy(newLog, mInfoLog);
2405 strcpy(newLog + logLength, info);
2406
2407 delete[] mInfoLog;
2408 mInfoLog = newLog;
2409 }
2410}
2411
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002412void Program::resetInfoLog()
2413{
2414 if (mInfoLog)
2415 {
2416 delete [] mInfoLog;
daniel@transgaming.com6a20d102010-08-31 13:54:27 +00002417 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002418 }
2419}
2420
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002421// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
2422void Program::unlink(bool destroy)
2423{
2424 if (destroy) // Object being destructed
2425 {
2426 if (mFragmentShader)
2427 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002428 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002429 mFragmentShader = NULL;
2430 }
2431
2432 if (mVertexShader)
2433 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002434 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002435 mVertexShader = NULL;
2436 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002437 }
2438
2439 if (mPixelExecutable)
2440 {
2441 mPixelExecutable->Release();
2442 mPixelExecutable = NULL;
2443 }
2444
2445 if (mVertexExecutable)
2446 {
2447 mVertexExecutable->Release();
2448 mVertexExecutable = NULL;
2449 }
2450
2451 if (mConstantTablePS)
2452 {
2453 mConstantTablePS->Release();
2454 mConstantTablePS = NULL;
2455 }
2456
2457 if (mConstantTableVS)
2458 {
2459 mConstantTableVS->Release();
2460 mConstantTableVS = NULL;
2461 }
2462
2463 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2464 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002465 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002466 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002467 }
2468
2469 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2470 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00002471 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002472 }
2473
2474 while (!mUniforms.empty())
2475 {
2476 delete mUniforms.back();
2477 mUniforms.pop_back();
2478 }
2479
daniel@transgaming.com31754962010-11-28 02:02:52 +00002480 mDxDepthRangeLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002481 mDxDepthLocation = -1;
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002482 mDxViewportLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002483 mDxHalfPixelSizeLocation = -1;
2484 mDxFrontCCWLocation = -1;
2485 mDxPointsOrLinesLocation = -1;
2486
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002487 mUniformIndex.clear();
2488
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002489 mPixelHLSL.clear();
2490 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002491
2492 delete[] mInfoLog;
2493 mInfoLog = NULL;
2494
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002495 mLinked = false;
2496}
2497
2498bool Program::isLinked()
2499{
2500 return mLinked;
2501}
2502
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002503bool Program::isValidated() const
2504{
2505 return mValidated;
2506}
2507
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002508void Program::release()
2509{
2510 mRefCount--;
2511
2512 if (mRefCount == 0 && mDeleteStatus)
2513 {
2514 mResourceManager->deleteProgram(mHandle);
2515 }
2516}
2517
2518void Program::addRef()
2519{
2520 mRefCount++;
2521}
2522
2523unsigned int Program::getRefCount() const
2524{
2525 return mRefCount;
2526}
2527
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002528unsigned int Program::getSerial() const
2529{
2530 return mSerial;
2531}
2532
2533unsigned int Program::issueSerial()
2534{
2535 return mCurrentSerial++;
2536}
2537
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002538int Program::getInfoLogLength() const
2539{
2540 if (!mInfoLog)
2541 {
2542 return 0;
2543 }
2544 else
2545 {
2546 return strlen(mInfoLog) + 1;
2547 }
2548}
2549
2550void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2551{
2552 int index = 0;
2553
2554 if (mInfoLog)
2555 {
2556 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2557 {
2558 infoLog[index] = mInfoLog[index];
2559 index++;
2560 }
2561 }
2562
2563 if (bufSize)
2564 {
2565 infoLog[index] = '\0';
2566 }
2567
2568 if (length)
2569 {
2570 *length = index;
2571 }
2572}
2573
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002574void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2575{
2576 int total = 0;
2577
2578 if (mVertexShader)
2579 {
2580 if (total < maxCount)
2581 {
2582 shaders[total] = mVertexShader->getHandle();
2583 }
2584
2585 total++;
2586 }
2587
2588 if (mFragmentShader)
2589 {
2590 if (total < maxCount)
2591 {
2592 shaders[total] = mFragmentShader->getHandle();
2593 }
2594
2595 total++;
2596 }
2597
2598 if (count)
2599 {
2600 *count = total;
2601 }
2602}
2603
daniel@transgaming.com85423182010-04-22 13:35:27 +00002604void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2605{
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002606 // Skip over inactive attributes
2607 unsigned int activeAttribute = 0;
2608 unsigned int attribute;
2609 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
daniel@transgaming.com85423182010-04-22 13:35:27 +00002610 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002611 if (mLinkedAttribute[attribute].name.empty())
daniel@transgaming.com85423182010-04-22 13:35:27 +00002612 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002613 continue;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002614 }
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002615
2616 if (activeAttribute == index)
2617 {
2618 break;
2619 }
2620
2621 activeAttribute++;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002622 }
2623
2624 if (bufsize > 0)
2625 {
2626 const char *string = mLinkedAttribute[attribute].name.c_str();
2627
2628 strncpy(name, string, bufsize);
2629 name[bufsize - 1] = '\0';
2630
2631 if (length)
2632 {
2633 *length = strlen(name);
2634 }
2635 }
2636
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002637 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002638
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002639 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002640}
2641
2642GLint Program::getActiveAttributeCount()
2643{
2644 int count = 0;
2645
2646 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2647 {
2648 if (!mLinkedAttribute[attributeIndex].name.empty())
2649 {
2650 count++;
2651 }
2652 }
2653
2654 return count;
2655}
2656
2657GLint Program::getActiveAttributeMaxLength()
2658{
2659 int maxLength = 0;
2660
2661 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2662 {
2663 if (!mLinkedAttribute[attributeIndex].name.empty())
2664 {
2665 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2666 }
2667 }
2668
2669 return maxLength;
2670}
2671
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002672void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2673{
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002674 // Skip over internal uniforms
2675 unsigned int activeUniform = 0;
2676 unsigned int uniform;
2677 for (uniform = 0; uniform < mUniforms.size(); uniform++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002678 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002679 if (mUniforms[uniform]->name.substr(0, 3) == "dx_")
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002680 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002681 continue;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002682 }
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002683
2684 if (activeUniform == index)
2685 {
2686 break;
2687 }
2688
2689 activeUniform++;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002690 }
2691
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002692 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2693
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002694 if (bufsize > 0)
2695 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002696 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002697
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002698 if (mUniforms[uniform]->arraySize != 1)
2699 {
2700 string += "[0]";
2701 }
2702
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002703 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002704 name[bufsize - 1] = '\0';
2705
2706 if (length)
2707 {
2708 *length = strlen(name);
2709 }
2710 }
2711
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002712 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002713
2714 *type = mUniforms[uniform]->type;
2715}
2716
2717GLint Program::getActiveUniformCount()
2718{
2719 int count = 0;
2720
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002721 unsigned int numUniforms = mUniforms.size();
2722 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002723 {
2724 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2725 {
2726 count++;
2727 }
2728 }
2729
2730 return count;
2731}
2732
2733GLint Program::getActiveUniformMaxLength()
2734{
2735 int maxLength = 0;
2736
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002737 unsigned int numUniforms = mUniforms.size();
2738 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002739 {
2740 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2741 {
zmo@google.com53d73e02011-03-24 21:27:57 +00002742 int length = (int)(undecorate(mUniforms[uniformIndex]->name).length() + 1);
zmo@google.com2a5645f2011-03-24 21:36:51 +00002743 if (mUniforms[uniformIndex]->arraySize != 1)
zmo@google.com53d73e02011-03-24 21:27:57 +00002744 {
2745 length += 3; // Counting in "[0]".
2746 }
2747 maxLength = std::max(length, maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002748 }
2749 }
2750
2751 return maxLength;
2752}
2753
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002754void Program::flagForDeletion()
2755{
2756 mDeleteStatus = true;
2757}
2758
2759bool Program::isFlaggedForDeletion() const
2760{
2761 return mDeleteStatus;
2762}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002763
2764void Program::validate()
2765{
2766 resetInfoLog();
2767
2768 if (!isLinked())
2769 {
2770 appendToInfoLog("Program has not been successfully linked.");
2771 mValidated = false;
2772 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002773 else
2774 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002775 applyUniforms();
2776 if (!validateSamplers())
2777 {
2778 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2779 mValidated = false;
2780 }
2781 else
2782 {
2783 mValidated = true;
2784 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002785 }
2786}
2787
2788bool Program::validateSamplers() const
2789{
2790 // if any two active samplers in a program are of different types, but refer to the same
2791 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2792 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2793 std::map<int, SamplerType> samplerMap;
2794 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2795 {
2796 if (mSamplers[i].active)
2797 {
2798 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2799 {
2800 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2801 return false;
2802 }
2803 else
2804 {
2805 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2806 }
2807 }
2808 }
2809
2810 return true;
2811}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002812
2813void Program::getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS)
2814{
2815 if (!targetUniform->handlesSet)
2816 {
2817 targetUniform->psHandle = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2818 targetUniform->vsHandle = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
2819 targetUniform->handlesSet = true;
2820 }
2821
2822 *constantPS = targetUniform->psHandle;
2823 *constantVS = targetUniform->vsHandle;
2824}
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002825
daniel@transgaming.com31754962010-11-28 02:02:52 +00002826GLint Program::getDxDepthRangeLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002827{
daniel@transgaming.com31754962010-11-28 02:02:52 +00002828 return mDxDepthRangeLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002829}
2830
2831GLint Program::getDxDepthLocation() const
2832{
2833 return mDxDepthLocation;
2834}
2835
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002836GLint Program::getDxViewportLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002837{
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002838 return mDxViewportLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002839}
2840
2841GLint Program::getDxHalfPixelSizeLocation() const
2842{
2843 return mDxHalfPixelSizeLocation;
2844}
2845
2846GLint Program::getDxFrontCCWLocation() const
2847{
2848 return mDxFrontCCWLocation;
2849}
2850
2851GLint Program::getDxPointsOrLinesLocation() const
2852{
2853 return mDxPointsOrLinesLocation;
2854}
2855
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002856}