blob: 8ed4d4178c74f711e8c6e8ce5d6cfb34dc37d337 [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{
189 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
190 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000191 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000192 }
193
194 return -1;
195}
196
197// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
198// index referenced in the compiled HLSL shader
199GLint Program::getSamplerMapping(unsigned int samplerIndex)
200{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000201 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
202
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000203 GLint logicalTextureUnit = -1;
204
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000205 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000206 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000207 logicalTextureUnit = mSamplers[samplerIndex].logicalTextureUnit;
208 }
209
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +0000210 if (logicalTextureUnit >= 0 && logicalTextureUnit < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000211 {
212 return logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000213 }
214
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000215 return -1;
216}
217
218SamplerType Program::getSamplerType(unsigned int samplerIndex)
219{
220 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
221 assert(mSamplers[samplerIndex].active);
222
223 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000224}
225
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000226GLint Program::getUniformLocation(const char *name, bool decorated)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000227{
daniel@transgaming.comce864422010-11-18 13:16:49 +0000228 std::string _name = decorated ? name : decorate(name);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000229 int subscript = 0;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000230
daniel@transgaming.comce864422010-11-18 13:16:49 +0000231 // Strip any trailing array operator and retrieve the subscript
232 size_t open = _name.find_last_of('[');
233 size_t close = _name.find_last_of(']');
234 if (open != std::string::npos && close == _name.length() - 1)
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000235 {
daniel@transgaming.comce864422010-11-18 13:16:49 +0000236 subscript = atoi(_name.substr(open + 1).c_str());
237 _name.erase(open);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000238 }
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000239
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000240 unsigned int numUniforms = mUniformIndex.size();
241 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000242 {
daniel@transgaming.comce864422010-11-18 13:16:49 +0000243 if (mUniformIndex[location].name == _name &&
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000244 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000245 {
246 return location;
247 }
248 }
249
250 return -1;
251}
252
253bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
254{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000255 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000256 {
257 return false;
258 }
259
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000260 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000261 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000262
263 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000264 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000265 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000266
267 if (arraySize == 1 && count > 1)
268 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
269
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000270 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000271
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000272 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
273 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000274 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000275 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000276 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000277 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000278
279 if (arraySize == 1 && count > 1)
280 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000281
282 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000283 GLboolean *boolParams = new GLboolean[count];
284
285 for (int i = 0; i < count; ++i)
286 {
287 if (v[i] == 0.0f)
288 {
289 boolParams[i] = GL_FALSE;
290 }
291 else
292 {
293 boolParams[i] = GL_TRUE;
294 }
295 }
296
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000297 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
298 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000299
300 delete [] boolParams;
301 }
302 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000303 {
304 return false;
305 }
306
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000307 return true;
308}
309
310bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
311{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000312 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000313 {
314 return false;
315 }
316
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000317 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000318 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000319
320 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000321 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000322 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000323
324 if (arraySize == 1 && count > 1)
325 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
326
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000327 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000328
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000329 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
330 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000331 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000332 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000333 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000334 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000335
336 if (arraySize == 1 && count > 1)
337 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
338
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000339 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
340
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000341 GLboolean *boolParams = new GLboolean[count * 2];
342
343 for (int i = 0; i < count * 2; ++i)
344 {
345 if (v[i] == 0.0f)
346 {
347 boolParams[i] = GL_FALSE;
348 }
349 else
350 {
351 boolParams[i] = GL_TRUE;
352 }
353 }
354
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000355 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
356 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000357
358 delete [] boolParams;
359 }
360 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000361 {
362 return false;
363 }
364
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000365 return true;
366}
367
368bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
369{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000370 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000371 {
372 return false;
373 }
374
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000375 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000376 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000377
378 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000379 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000380 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000381
382 if (arraySize == 1 && count > 1)
383 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
384
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000385 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000386
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000387 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
388 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000389 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000390 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000391 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000392 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000393
394 if (arraySize == 1 && count > 1)
395 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
396
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000397 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000398 GLboolean *boolParams = new GLboolean[count * 3];
399
400 for (int i = 0; i < count * 3; ++i)
401 {
402 if (v[i] == 0.0f)
403 {
404 boolParams[i] = GL_FALSE;
405 }
406 else
407 {
408 boolParams[i] = GL_TRUE;
409 }
410 }
411
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000412 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
413 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000414
415 delete [] boolParams;
416 }
417 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000418 {
419 return false;
420 }
421
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000422 return true;
423}
424
425bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
426{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000427 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000428 {
429 return false;
430 }
431
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000432 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000433 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000434
435 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000436 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000437 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000438
439 if (arraySize == 1 && count > 1)
440 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
441
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000442 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000443
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000444 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
445 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000446 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000447 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000448 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000449 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000450
451 if (arraySize == 1 && count > 1)
452 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
453
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000454 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000455 GLboolean *boolParams = new GLboolean[count * 4];
456
457 for (int i = 0; i < count * 4; ++i)
458 {
459 if (v[i] == 0.0f)
460 {
461 boolParams[i] = GL_FALSE;
462 }
463 else
464 {
465 boolParams[i] = GL_TRUE;
466 }
467 }
468
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000469 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
470 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000471
472 delete [] boolParams;
473 }
474 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000475 {
476 return false;
477 }
478
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000479 return true;
480}
481
482bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
483{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000484 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000485 {
486 return false;
487 }
488
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000489 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000490 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000491
492 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000493 {
494 return false;
495 }
496
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000497 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000498
499 if (arraySize == 1 && count > 1)
500 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
501
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000502 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000503
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000504 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
505 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000506
507 return true;
508}
509
510bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
511{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000512 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000513 {
514 return false;
515 }
516
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000517 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000518 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000519
520 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000521 {
522 return false;
523 }
524
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000525 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000526
527 if (arraySize == 1 && count > 1)
528 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
529
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000530 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000531
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000532 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
533 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000534
535 return true;
536}
537
538bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
539{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000540 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000541 {
542 return false;
543 }
544
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000545 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000546 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000547
548 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000549 {
550 return false;
551 }
552
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000553 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000554
555 if (arraySize == 1 && count > 1)
556 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
557
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000558 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000559
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000560 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
561 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000562
563 return true;
564}
565
566bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
567{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000568 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000569 {
570 return false;
571 }
572
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000573 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000574 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000575
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000576 if (targetUniform->type == GL_INT ||
577 targetUniform->type == GL_SAMPLER_2D ||
578 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000579 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000580 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000581
582 if (arraySize == 1 && count > 1)
583 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
584
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000585 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000586
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000587 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
588 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000589 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000590 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000591 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000592 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000593
594 if (arraySize == 1 && count > 1)
595 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
596
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000597 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000598 GLboolean *boolParams = new GLboolean[count];
599
600 for (int i = 0; i < count; ++i)
601 {
602 if (v[i] == 0)
603 {
604 boolParams[i] = GL_FALSE;
605 }
606 else
607 {
608 boolParams[i] = GL_TRUE;
609 }
610 }
611
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000612 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
613 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000614
615 delete [] boolParams;
616 }
617 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000618 {
619 return false;
620 }
621
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000622 return true;
623}
624
625bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
626{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000627 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000628 {
629 return false;
630 }
631
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000632 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000633 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000634
635 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000636 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000637 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000638
639 if (arraySize == 1 && count > 1)
640 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
641
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000642 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000643
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000644 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
645 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000646 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000647 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000648 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000649 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000650
651 if (arraySize == 1 && count > 1)
652 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
653
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000654 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000655 GLboolean *boolParams = new GLboolean[count * 2];
656
657 for (int i = 0; i < count * 2; ++i)
658 {
659 if (v[i] == 0)
660 {
661 boolParams[i] = GL_FALSE;
662 }
663 else
664 {
665 boolParams[i] = GL_TRUE;
666 }
667 }
668
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000669 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
670 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000671
672 delete [] boolParams;
673 }
674 else
675 {
676 return false;
677 }
678
679 return true;
680}
681
682bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
683{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000684 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000685 {
686 return false;
687 }
688
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000689 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000690 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000691
692 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000693 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000694 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000695
696 if (arraySize == 1 && count > 1)
697 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
698
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000699 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000700
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000701 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
702 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000703 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000704 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000705 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000706 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000707
708 if (arraySize == 1 && count > 1)
709 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
710
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000711 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000712 GLboolean *boolParams = new GLboolean[count * 3];
713
714 for (int i = 0; i < count * 3; ++i)
715 {
716 if (v[i] == 0)
717 {
718 boolParams[i] = GL_FALSE;
719 }
720 else
721 {
722 boolParams[i] = GL_TRUE;
723 }
724 }
725
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000726 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
727 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000728
729 delete [] boolParams;
730 }
731 else
732 {
733 return false;
734 }
735
736 return true;
737}
738
739bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
740{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000741 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000742 {
743 return false;
744 }
745
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000746 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000747 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000748
749 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000750 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000751 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000752
753 if (arraySize == 1 && count > 1)
754 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
755
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000756 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000757
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000758 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
759 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000760 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000761 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000762 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000763 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000764
765 if (arraySize == 1 && count > 1)
766 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
767
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000768 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000769 GLboolean *boolParams = new GLboolean[count * 4];
770
771 for (int i = 0; i < count * 4; ++i)
772 {
773 if (v[i] == 0)
774 {
775 boolParams[i] = GL_FALSE;
776 }
777 else
778 {
779 boolParams[i] = GL_TRUE;
780 }
781 }
782
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000783 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
784 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000785
786 delete [] boolParams;
787 }
788 else
789 {
790 return false;
791 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000792
793 return true;
794}
795
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000796bool Program::getUniformfv(GLint location, GLfloat *params)
797{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000798 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000799 {
800 return false;
801 }
802
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000803 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000804
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000805 unsigned int count = UniformComponentCount(targetUniform->type);
806
807 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000808 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000809 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000810 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000811 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000812
813 for (unsigned int i = 0; i < count; ++i)
814 {
815 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
816 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000817 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000818 break;
819 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000820 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
821 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000822 break;
823 case GL_INT:
824 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000825 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000826
827 for (unsigned int i = 0; i < count; ++i)
828 {
829 params[i] = (float)intParams[i];
830 }
831 }
832 break;
833 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000834 }
835
836 return true;
837}
838
839bool Program::getUniformiv(GLint location, GLint *params)
840{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000841 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000842 {
843 return false;
844 }
845
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000846 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000847
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000848 unsigned int count = UniformComponentCount(targetUniform->type);
849
850 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000851 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000852 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000853 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000854 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000855
856 for (unsigned int i = 0; i < count; ++i)
857 {
858 params[i] = (GLint)boolParams[i];
859 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000860 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000861 break;
862 case GL_FLOAT:
863 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000864 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000865
866 for (unsigned int i = 0; i < count; ++i)
867 {
868 params[i] = (GLint)floatParams[i];
869 }
870 }
871 break;
872 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000873 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
874 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000875 break;
876 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000877 }
878
879 return true;
880}
881
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000882void Program::dirtyAllUniforms()
883{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000884 unsigned int numUniforms = mUniforms.size();
885 for (unsigned int index = 0; index < numUniforms; index++)
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000886 {
887 mUniforms[index]->dirty = true;
888 }
889}
890
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000891// Applies all the uniforms set for this program object to the Direct3D 9 device
892void Program::applyUniforms()
893{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000894 unsigned int numUniforms = mUniformIndex.size();
895 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000896 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000897 if (mUniformIndex[location].element != 0)
898 {
899 continue;
900 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000901
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000902 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
903
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000904 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000905 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000906 int arraySize = targetUniform->arraySize;
907 GLfloat *f = (GLfloat*)targetUniform->data;
908 GLint *i = (GLint*)targetUniform->data;
909 GLboolean *b = (GLboolean*)targetUniform->data;
910
911 switch (targetUniform->type)
912 {
913 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
914 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
915 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
916 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
917 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
918 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
919 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
920 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
921 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
922 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
923 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000924 case GL_SAMPLER_2D:
925 case GL_SAMPLER_CUBE:
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000926 case GL_INT: applyUniform1iv(location, arraySize, i); break;
927 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
928 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
929 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
930 default:
931 UNREACHABLE();
932 }
933
934 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000935 }
936 }
937}
938
939// Compiles the HLSL code of the attached shaders into executable binaries
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000940ID3D10Blob *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000941{
942 if (!hlsl)
943 {
944 return NULL;
945 }
946
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000947 DWORD result;
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000948 UINT flags = 0;
949 std::string sourceText;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000950 if (perfActive())
951 {
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000952 flags |= D3DCOMPILE_DEBUG;
953#ifdef NDEBUG
954 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
955#else
956 flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000957#endif
958
959 std::string sourcePath = getTempPath();
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000960 sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000961 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000962 }
963 else
964 {
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000965 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
966 sourceText = hlsl;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000967 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000968
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000969 ID3D10Blob *binary = NULL;
970 ID3D10Blob *errorMessage = NULL;
971 result = D3DCompile(hlsl, strlen(hlsl), NULL, NULL, NULL, "main", profile, flags, 0, &binary, &errorMessage);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000972
973 if (errorMessage)
974 {
975 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000976
daniel@transgaming.com0df16872010-05-12 16:51:08 +0000977 appendToInfoLog("%s\n", message);
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000978 TRACE("\n%s", hlsl);
979 TRACE("\n%s", message);
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000980
981 errorMessage->Release();
982 errorMessage = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000983 }
984
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000985
986 if (FAILED(result))
987 {
988 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
989 {
990 error(GL_OUT_OF_MEMORY);
991 }
992
993 return NULL;
994 }
995
996 result = D3DXGetShaderConstantTable(static_cast<const DWORD*>(binary->GetBufferPointer()), constantTable);
997
998 if (FAILED(result))
999 {
1000 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1001 {
1002 error(GL_OUT_OF_MEMORY);
1003 }
1004
1005 binary->Release();
1006
1007 return NULL;
1008 }
1009
1010 return binary;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001011}
1012
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001013// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1014// Returns the number of used varying registers, or -1 if unsuccesful
1015int Program::packVaryings(const Varying *packing[][4])
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001016{
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001017 Context *context = getContext();
1018 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1019
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001020 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001021 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001022 int n = VariableRowCount(varying->type) * varying->size;
1023 int m = VariableColumnCount(varying->type);
1024 bool success = false;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001025
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001026 if (m == 2 || m == 3 || m == 4)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001027 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001028 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001029 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001030 bool available = true;
1031
1032 for (int y = 0; y < n && available; y++)
1033 {
1034 for (int x = 0; x < m && available; x++)
1035 {
1036 if (packing[r + y][x])
1037 {
1038 available = false;
1039 }
1040 }
1041 }
1042
1043 if (available)
1044 {
1045 varying->reg = r;
1046 varying->col = 0;
1047
1048 for (int y = 0; y < n; y++)
1049 {
1050 for (int x = 0; x < m; x++)
1051 {
1052 packing[r + y][x] = &*varying;
1053 }
1054 }
1055
1056 success = true;
1057 }
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001058 }
1059
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001060 if (!success && m == 2)
1061 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001062 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001063 {
1064 bool available = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001065
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001066 for (int y = 0; y < n && available; y++)
1067 {
1068 for (int x = 2; x < 4 && available; x++)
1069 {
1070 if (packing[r + y][x])
1071 {
1072 available = false;
1073 }
1074 }
1075 }
1076
1077 if (available)
1078 {
1079 varying->reg = r;
1080 varying->col = 2;
1081
1082 for (int y = 0; y < n; y++)
1083 {
1084 for (int x = 2; x < 4; x++)
1085 {
1086 packing[r + y][x] = &*varying;
1087 }
1088 }
1089
1090 success = true;
1091 }
1092 }
1093 }
1094 }
1095 else if (m == 1)
1096 {
1097 int space[4] = {0};
1098
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001099 for (int y = 0; y < maxVaryingVectors; y++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001100 {
1101 for (int x = 0; x < 4; x++)
1102 {
1103 space[x] += packing[y][x] ? 0 : 1;
1104 }
1105 }
1106
1107 int column = 0;
1108
1109 for (int x = 0; x < 4; x++)
1110 {
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001111 if (space[x] >= n && space[x] < space[column])
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001112 {
1113 column = x;
1114 }
1115 }
1116
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001117 if (space[column] >= n)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001118 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001119 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001120 {
1121 if (!packing[r][column])
1122 {
1123 varying->reg = r;
1124
1125 for (int y = r; y < r + n; y++)
1126 {
1127 packing[y][column] = &*varying;
1128 }
1129
1130 break;
1131 }
1132 }
1133
1134 varying->col = column;
1135
1136 success = true;
1137 }
1138 }
1139 else UNREACHABLE();
1140
1141 if (!success)
1142 {
1143 appendToInfoLog("Could not pack varying %s", varying->name.c_str());
1144
1145 return -1;
1146 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001147 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001148
1149 // Return the number of used registers
1150 int registers = 0;
1151
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001152 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001153 {
1154 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1155 {
1156 registers++;
1157 }
1158 }
1159
1160 return registers;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001161}
1162
1163bool Program::linkVaryings()
1164{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001165 if (mPixelHLSL.empty() || mVertexHLSL.empty())
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001166 {
1167 return false;
1168 }
1169
daniel@transgaming.com97750022011-02-11 13:23:13 +00001170 // Reset the varying register assignments
1171 for (VaryingList::iterator fragVar = mFragmentShader->varyings.begin(); fragVar != mFragmentShader->varyings.end(); fragVar++)
1172 {
1173 fragVar->reg = -1;
1174 fragVar->col = -1;
1175 }
1176
1177 for (VaryingList::iterator vtxVar = mVertexShader->varyings.begin(); vtxVar != mVertexShader->varyings.end(); vtxVar++)
1178 {
1179 vtxVar->reg = -1;
1180 vtxVar->col = -1;
1181 }
1182
1183 // Map the varyings to the register file
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001184 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001185 int registers = packVaryings(packing);
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001186
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001187 if (registers < 0)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001188 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001189 return false;
1190 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001191
daniel@transgaming.com97750022011-02-11 13:23:13 +00001192 // Write the HLSL input/output declarations
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001193 Context *context = getContext();
1194 const bool sm3 = context->supportsShaderModel3();
1195 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1196
1197 if (registers == maxVaryingVectors && mFragmentShader->mUsesFragCoord)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001198 {
1199 appendToInfoLog("No varying registers left to support gl_FragCoord");
1200
1201 return false;
1202 }
1203
1204 for (VaryingList::iterator input = mFragmentShader->varyings.begin(); input != mFragmentShader->varyings.end(); input++)
1205 {
1206 bool matched = false;
1207
1208 for (VaryingList::iterator output = mVertexShader->varyings.begin(); output != mVertexShader->varyings.end(); output++)
1209 {
1210 if (output->name == input->name)
1211 {
1212 if (output->type != input->type || output->size != input->size)
1213 {
1214 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
1215
1216 return false;
1217 }
1218
1219 output->reg = input->reg;
1220 output->col = input->col;
1221
1222 matched = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001223 break;
1224 }
1225 }
1226
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001227 if (!matched)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001228 {
daniel@transgaming.com97750022011-02-11 13:23:13 +00001229 appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001230
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001231 return false;
1232 }
1233 }
1234
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001235 std::string varyingSemantic = (sm3 ? "COLOR" : "TEXCOORD");
1236
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001237 mVertexHLSL += "struct VS_INPUT\n"
1238 "{\n";
1239
1240 int semanticIndex = 0;
1241 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1242 {
1243 switch (attribute->type)
1244 {
1245 case GL_FLOAT: mVertexHLSL += " float "; break;
1246 case GL_FLOAT_VEC2: mVertexHLSL += " float2 "; break;
1247 case GL_FLOAT_VEC3: mVertexHLSL += " float3 "; break;
1248 case GL_FLOAT_VEC4: mVertexHLSL += " float4 "; break;
1249 case GL_FLOAT_MAT2: mVertexHLSL += " float2x2 "; break;
1250 case GL_FLOAT_MAT3: mVertexHLSL += " float3x3 "; break;
1251 case GL_FLOAT_MAT4: mVertexHLSL += " float4x4 "; break;
1252 default: UNREACHABLE();
1253 }
1254
1255 mVertexHLSL += decorate(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1256
1257 semanticIndex += VariableRowCount(attribute->type);
1258 }
1259
1260 mVertexHLSL += "};\n"
1261 "\n"
1262 "struct VS_OUTPUT\n"
1263 "{\n"
1264 " float4 gl_Position : POSITION;\n";
1265
1266 for (int r = 0; r < registers; r++)
1267 {
1268 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1269
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001270 mVertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001271 }
1272
1273 if (mFragmentShader->mUsesFragCoord)
1274 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001275 mVertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1276 }
1277
1278 if (mVertexShader->mUsesPointSize && sm3)
1279 {
1280 mVertexHLSL += " float gl_PointSize : PSIZE;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001281 }
1282
1283 mVertexHLSL += "};\n"
1284 "\n"
1285 "VS_OUTPUT main(VS_INPUT input)\n"
1286 "{\n";
1287
1288 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1289 {
1290 mVertexHLSL += " " + decorate(attribute->name) + " = ";
1291
1292 if (VariableRowCount(attribute->type) > 1) // Matrix
1293 {
1294 mVertexHLSL += "transpose";
1295 }
1296
1297 mVertexHLSL += "(input." + decorate(attribute->name) + ");\n";
1298 }
1299
1300 mVertexHLSL += "\n"
1301 " gl_main();\n"
1302 "\n"
1303 " VS_OUTPUT output;\n"
1304 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001305 " output.gl_Position.y = gl_Position.y - dx_HalfPixelSize.y * gl_Position.w;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001306 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1307 " output.gl_Position.w = gl_Position.w;\n";
1308
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001309 if (mVertexShader->mUsesPointSize && sm3)
1310 {
1311 mVertexHLSL += " output.gl_PointSize = clamp(gl_PointSize, 1.0, " + str((int)ALIASED_POINT_SIZE_RANGE_MAX_SM3) + ");\n";
1312 }
1313
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001314 if (mFragmentShader->mUsesFragCoord)
1315 {
1316 mVertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1317 }
1318
1319 for (VaryingList::iterator varying = mVertexShader->varyings.begin(); varying != mVertexShader->varyings.end(); varying++)
1320 {
1321 if (varying->reg >= 0)
1322 {
1323 for (int i = 0; i < varying->size; i++)
1324 {
1325 int rows = VariableRowCount(varying->type);
1326
1327 for (int j = 0; j < rows; j++)
1328 {
1329 int r = varying->reg + i * rows + j;
1330 mVertexHLSL += " output.v" + str(r);
1331
1332 bool sharedRegister = false; // Register used by multiple varyings
1333
1334 for (int x = 0; x < 4; x++)
1335 {
1336 if (packing[r][x] && packing[r][x] != packing[r][0])
1337 {
1338 sharedRegister = true;
1339 break;
1340 }
1341 }
1342
1343 if(sharedRegister)
1344 {
1345 mVertexHLSL += ".";
1346
1347 for (int x = 0; x < 4; x++)
1348 {
1349 if (packing[r][x] == &*varying)
1350 {
1351 switch(x)
1352 {
1353 case 0: mVertexHLSL += "x"; break;
1354 case 1: mVertexHLSL += "y"; break;
1355 case 2: mVertexHLSL += "z"; break;
1356 case 3: mVertexHLSL += "w"; break;
1357 }
1358 }
1359 }
1360 }
1361
1362 mVertexHLSL += " = " + varying->name;
1363
1364 if (varying->array)
1365 {
1366 mVertexHLSL += "[" + str(i) + "]";
1367 }
1368
1369 if (rows > 1)
1370 {
1371 mVertexHLSL += "[" + str(j) + "]";
1372 }
1373
1374 mVertexHLSL += ";\n";
1375 }
1376 }
1377 }
1378 }
1379
1380 mVertexHLSL += "\n"
1381 " return output;\n"
1382 "}\n";
1383
1384 mPixelHLSL += "struct PS_INPUT\n"
1385 "{\n";
1386
1387 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1388 {
1389 if (varying->reg >= 0)
1390 {
1391 for (int i = 0; i < varying->size; i++)
1392 {
1393 int rows = VariableRowCount(varying->type);
1394 for (int j = 0; j < rows; j++)
1395 {
1396 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001397 mPixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001398 }
1399 }
1400 }
1401 else UNREACHABLE();
1402 }
1403
1404 if (mFragmentShader->mUsesFragCoord)
1405 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001406 mPixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001407 if (sm3) {
daniel@transgaming.com996675c2010-11-17 13:06:29 +00001408 mPixelHLSL += " float2 dx_VPos : VPOS;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001409 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001410 }
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001411
1412 if (mFragmentShader->mUsesPointCoord && sm3)
1413 {
1414 mPixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1415 }
1416
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001417 if (mFragmentShader->mUsesFrontFacing)
1418 {
1419 mPixelHLSL += " float vFace : VFACE;\n";
1420 }
1421
1422 mPixelHLSL += "};\n"
1423 "\n"
1424 "struct PS_OUTPUT\n"
1425 "{\n"
1426 " float4 gl_Color[1] : COLOR;\n"
1427 "};\n"
1428 "\n"
1429 "PS_OUTPUT main(PS_INPUT input)\n"
1430 "{\n";
1431
1432 if (mFragmentShader->mUsesFragCoord)
1433 {
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001434 mPixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1435 if (sm3) {
1436 mPixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001437 " gl_FragCoord.y = 2.0 * dx_Viewport.y - input.dx_VPos.y;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001438 } else {
1439 mPixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Viewport.x + dx_Viewport.z;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001440 " gl_FragCoord.y = -(input.gl_FragCoord.y * rhw) * dx_Viewport.y + dx_Viewport.w;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001441 }
1442 mPixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001443 " gl_FragCoord.w = rhw;\n";
1444 }
1445
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001446 if (mFragmentShader->mUsesPointCoord && sm3)
1447 {
apatrick@chromium.orgda4d0492011-01-22 00:16:10 +00001448 mPixelHLSL += " gl_PointCoord = input.gl_PointCoord;\n";
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001449 }
1450
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001451 if (mFragmentShader->mUsesFrontFacing)
1452 {
1453 mPixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1454 }
1455
1456 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1457 {
1458 if (varying->reg >= 0)
1459 {
1460 for (int i = 0; i < varying->size; i++)
1461 {
1462 int rows = VariableRowCount(varying->type);
1463 for (int j = 0; j < rows; j++)
1464 {
1465 std::string n = str(varying->reg + i * rows + j);
1466 mPixelHLSL += " " + varying->name;
1467
1468 if (varying->array)
1469 {
1470 mPixelHLSL += "[" + str(i) + "]";
1471 }
1472
1473 if (rows > 1)
1474 {
1475 mPixelHLSL += "[" + str(j) + "]";
1476 }
1477
1478 mPixelHLSL += " = input.v" + n + ";\n";
1479 }
1480 }
1481 }
1482 else UNREACHABLE();
1483 }
1484
1485 mPixelHLSL += "\n"
1486 " gl_main();\n"
1487 "\n"
1488 " PS_OUTPUT output;\n"
1489 " output.gl_Color[0] = gl_Color[0];\n"
1490 "\n"
1491 " return output;\n"
1492 "}\n";
1493
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001494 return true;
1495}
1496
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001497// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1498// compiling them into binaries, determining the attribute mappings, and collecting
1499// a list of uniforms
1500void Program::link()
1501{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001502 unlink();
1503
1504 if (!mFragmentShader || !mFragmentShader->isCompiled())
1505 {
1506 return;
1507 }
1508
1509 if (!mVertexShader || !mVertexShader->isCompiled())
1510 {
1511 return;
1512 }
1513
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001514 mPixelHLSL = mFragmentShader->getHLSL();
1515 mVertexHLSL = mVertexShader->getHLSL();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001516
1517 if (!linkVaryings())
1518 {
1519 return;
1520 }
1521
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001522 Context *context = getContext();
1523 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1524 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1525
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001526 ID3D10Blob *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1527 ID3D10Blob *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001528
1529 if (vertexBinary && pixelBinary)
1530 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001531 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001532 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1533 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1534
1535 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1536 {
1537 return error(GL_OUT_OF_MEMORY);
1538 }
1539
1540 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001541
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001542 vertexBinary->Release();
1543 pixelBinary->Release();
1544 vertexBinary = NULL;
1545 pixelBinary = NULL;
1546
1547 if (mVertexExecutable && mPixelExecutable)
1548 {
1549 if (!linkAttributes())
1550 {
1551 return;
1552 }
1553
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001554 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001555 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001556 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001557 }
1558
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001559 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001560 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001561 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001562 }
1563
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001564 // these uniforms are searched as already-decorated because gl_ and dx_
1565 // are reserved prefixes, and do not receive additional decoration
daniel@transgaming.com31754962010-11-28 02:02:52 +00001566 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange", true);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001567 mDxDepthLocation = getUniformLocation("dx_Depth", true);
daniel@transgaming.com162267d2010-07-28 19:20:48 +00001568 mDxViewportLocation = getUniformLocation("dx_Viewport", true);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001569 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize", true);
1570 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW", true);
1571 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines", true);
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00001572
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001573 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001574 }
1575 }
1576}
1577
1578// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1579bool Program::linkAttributes()
1580{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001581 unsigned int usedLocations = 0;
1582
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001583 // Link attributes that have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001584 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001585 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001586 int location = getAttributeBinding(attribute->name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001587
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001588 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001589 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001590 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001591 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001592 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001593 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001594
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001595 mLinkedAttribute[location] = *attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001596
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001597 int rows = VariableRowCount(attribute->type);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001598
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001599 if (rows + location > MAX_VERTEX_ATTRIBS)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001600 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001601 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 +00001602
1603 return false;
1604 }
1605
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001606 for (int i = 0; i < rows; i++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001607 {
1608 usedLocations |= 1 << (location + i);
1609 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001610 }
1611 }
1612
1613 // Link attributes that don't have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001614 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001615 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001616 int location = getAttributeBinding(attribute->name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001617
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001618 if (location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001619 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001620 int rows = VariableRowCount(attribute->type);
1621 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001622
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001623 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001624 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001625 appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001626
1627 return false; // Fail to link
1628 }
1629
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001630 mLinkedAttribute[availableIndex] = *attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001631 }
1632 }
1633
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001634 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001635 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001636 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001637 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001638
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001639 for (int r = 0; r < rows; r++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001640 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001641 mSemanticIndex[attributeIndex++] = index++;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001642 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001643 }
1644
1645 return true;
1646}
1647
daniel@transgaming.com85423182010-04-22 13:35:27 +00001648int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001649{
1650 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1651 {
1652 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1653 {
1654 return location;
1655 }
1656 }
1657
1658 return -1;
1659}
1660
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001661bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1662{
1663 D3DXCONSTANTTABLE_DESC constantTableDescription;
1664 D3DXCONSTANT_DESC constantDescription;
1665 UINT descriptionCount = 1;
1666
1667 constantTable->GetDesc(&constantTableDescription);
1668
1669 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1670 {
1671 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1672 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1673
1674 if (!defineUniform(constantHandle, constantDescription))
1675 {
1676 return false;
1677 }
1678 }
1679
1680 return true;
1681}
1682
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001683// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001684// Returns true if succesful (uniform not already defined)
1685bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1686{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001687 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1688 {
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001689 for (unsigned int samplerIndex = constantDescription.RegisterIndex; samplerIndex < constantDescription.RegisterIndex + constantDescription.RegisterCount; samplerIndex++)
1690 {
1691 ASSERT(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001692
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001693 mSamplers[samplerIndex].active = true;
1694 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1695 mSamplers[samplerIndex].logicalTextureUnit = 0;
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001696 }
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001697 }
1698
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001699 switch(constantDescription.Class)
1700 {
1701 case D3DXPC_STRUCT:
1702 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001703 for (unsigned int arrayIndex = 0; arrayIndex < constantDescription.Elements; arrayIndex++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001704 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001705 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001706 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001707 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1708
1709 D3DXCONSTANT_DESC fieldDescription;
1710 UINT descriptionCount = 1;
1711
1712 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1713
1714 std::string structIndex = (constantDescription.Elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
1715
1716 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + structIndex + "."))
1717 {
1718 return false;
1719 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001720 }
1721 }
1722
1723 return true;
1724 }
1725 case D3DXPC_SCALAR:
1726 case D3DXPC_VECTOR:
1727 case D3DXPC_MATRIX_COLUMNS:
1728 case D3DXPC_OBJECT:
1729 return defineUniform(constantDescription, name + constantDescription.Name);
1730 default:
1731 UNREACHABLE();
1732 return false;
1733 }
1734}
1735
1736bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1737{
1738 Uniform *uniform = createUniform(constantDescription, name);
1739
1740 if(!uniform)
1741 {
1742 return false;
1743 }
1744
1745 // Check if already defined
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001746 GLint location = getUniformLocation(name.c_str(), true);
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001747 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001748
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001749 if (location >= 0)
1750 {
1751 delete uniform;
1752
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001753 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001754 {
1755 return false;
1756 }
1757 else
1758 {
1759 return true;
1760 }
1761 }
1762
1763 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001764 unsigned int uniformIndex = mUniforms.size() - 1;
1765
1766 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1767 {
1768 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1769 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001770
1771 return true;
1772}
1773
1774Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001775{
1776 if (constantDescription.Rows == 1) // Vectors and scalars
1777 {
1778 switch (constantDescription.Type)
1779 {
1780 case D3DXPT_SAMPLER2D:
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001781 switch (constantDescription.Columns)
1782 {
1783 case 1: return new Uniform(GL_SAMPLER_2D, name, constantDescription.Elements);
1784 default: UNREACHABLE();
1785 }
1786 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001787 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001788 switch (constantDescription.Columns)
1789 {
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001790 case 1: return new Uniform(GL_SAMPLER_CUBE, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001791 default: UNREACHABLE();
1792 }
1793 break;
1794 case D3DXPT_BOOL:
1795 switch (constantDescription.Columns)
1796 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001797 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1798 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1799 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1800 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001801 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001802 }
1803 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001804 case D3DXPT_INT:
1805 switch (constantDescription.Columns)
1806 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001807 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1808 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1809 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1810 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001811 default: UNREACHABLE();
1812 }
1813 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001814 case D3DXPT_FLOAT:
1815 switch (constantDescription.Columns)
1816 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001817 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1818 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1819 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1820 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001821 default: UNREACHABLE();
1822 }
1823 break;
1824 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001825 UNREACHABLE();
1826 }
1827 }
1828 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1829 {
1830 switch (constantDescription.Type)
1831 {
1832 case D3DXPT_FLOAT:
1833 switch (constantDescription.Rows)
1834 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001835 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1836 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1837 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001838 default: UNREACHABLE();
1839 }
1840 break;
1841 default: UNREACHABLE();
1842 }
1843 }
1844 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001845
1846 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001847}
1848
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001849// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001850std::string Program::decorate(const std::string &string)
1851{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001852 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001853 {
1854 return "_" + string;
1855 }
1856 else
1857 {
1858 return string;
1859 }
1860}
1861
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001862std::string Program::undecorate(const std::string &string)
1863{
1864 if (string.substr(0, 1) == "_")
1865 {
1866 return string.substr(1);
1867 }
1868 else
1869 {
1870 return string;
1871 }
1872}
1873
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001874bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1875{
1876 BOOL *vector = new BOOL[count];
1877 for (int i = 0; i < count; i++)
1878 {
1879 if (v[i] == GL_FALSE)
1880 vector[i] = 0;
1881 else
1882 vector[i] = 1;
1883 }
1884
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001885 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1886
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001887 D3DXHANDLE constantPS;
1888 D3DXHANDLE constantVS;
1889 getConstantHandles(targetUniform, &constantPS, &constantVS);
1890
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001891 IDirect3DDevice9 *device = getDevice();
1892
1893 if (constantPS)
1894 {
1895 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1896 }
1897
1898 if (constantVS)
1899 {
1900 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1901 }
1902
1903 delete [] vector;
1904
1905 return true;
1906}
1907
1908bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1909{
1910 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1911
1912 for (int i = 0; i < count; i++)
1913 {
1914 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1915 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1916
1917 v += 2;
1918 }
1919
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001920 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1921
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001922 D3DXHANDLE constantPS;
1923 D3DXHANDLE constantVS;
1924 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001925 IDirect3DDevice9 *device = getDevice();
1926
1927 if (constantPS)
1928 {
1929 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1930 }
1931
1932 if (constantVS)
1933 {
1934 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1935 }
1936
1937 delete[] vector;
1938
1939 return true;
1940}
1941
1942bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1943{
1944 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1945
1946 for (int i = 0; i < count; i++)
1947 {
1948 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1949 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1950 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1951
1952 v += 3;
1953 }
1954
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001955 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1956
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001957 D3DXHANDLE constantPS;
1958 D3DXHANDLE constantVS;
1959 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001960 IDirect3DDevice9 *device = getDevice();
1961
1962 if (constantPS)
1963 {
1964 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1965 }
1966
1967 if (constantVS)
1968 {
1969 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1970 }
1971
1972 delete[] vector;
1973
1974 return true;
1975}
1976
1977bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1978{
1979 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1980
1981 for (int i = 0; i < count; i++)
1982 {
1983 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1984 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1985 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1986 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1987
1988 v += 3;
1989 }
1990
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001991 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1992
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001993 D3DXHANDLE constantPS;
1994 D3DXHANDLE constantVS;
1995 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001996 IDirect3DDevice9 *device = getDevice();
1997
1998 if (constantPS)
1999 {
2000 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2001 }
2002
2003 if (constantVS)
2004 {
2005 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2006 }
2007
2008 delete [] vector;
2009
2010 return true;
2011}
2012
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002013bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
2014{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002015 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2016
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002017 D3DXHANDLE constantPS;
2018 D3DXHANDLE constantVS;
2019 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002020 IDirect3DDevice9 *device = getDevice();
2021
2022 if (constantPS)
2023 {
2024 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
2025 }
2026
2027 if (constantVS)
2028 {
2029 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
2030 }
2031
2032 return true;
2033}
2034
2035bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
2036{
2037 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2038
2039 for (int i = 0; i < count; i++)
2040 {
2041 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
2042
2043 v += 2;
2044 }
2045
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002046 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2047
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002048 D3DXHANDLE constantPS;
2049 D3DXHANDLE constantVS;
2050 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002051 IDirect3DDevice9 *device = getDevice();
2052
2053 if (constantPS)
2054 {
2055 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2056 }
2057
2058 if (constantVS)
2059 {
2060 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2061 }
2062
2063 delete[] vector;
2064
2065 return true;
2066}
2067
2068bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
2069{
2070 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2071
2072 for (int i = 0; i < count; i++)
2073 {
2074 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
2075
2076 v += 3;
2077 }
2078
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002079 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2080
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002081 D3DXHANDLE constantPS;
2082 D3DXHANDLE constantVS;
2083 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002084 IDirect3DDevice9 *device = getDevice();
2085
2086 if (constantPS)
2087 {
2088 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2089 }
2090
2091 if (constantVS)
2092 {
2093 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2094 }
2095
2096 delete[] vector;
2097
2098 return true;
2099}
2100
2101bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
2102{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002103 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2104
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002105 D3DXHANDLE constantPS;
2106 D3DXHANDLE constantVS;
2107 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002108 IDirect3DDevice9 *device = getDevice();
2109
2110 if (constantPS)
2111 {
2112 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
2113 }
2114
2115 if (constantVS)
2116 {
2117 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
2118 }
2119
2120 return true;
2121}
2122
2123bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
2124{
2125 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2126
2127 for (int i = 0; i < count; i++)
2128 {
2129 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
2130 value[1], value[3], 0, 0,
2131 0, 0, 1, 0,
2132 0, 0, 0, 1);
2133
2134 value += 4;
2135 }
2136
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002137 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2138
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002139 D3DXHANDLE constantPS;
2140 D3DXHANDLE constantVS;
2141 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002142 IDirect3DDevice9 *device = getDevice();
2143
2144 if (constantPS)
2145 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002146 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002147 }
2148
2149 if (constantVS)
2150 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002151 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002152 }
2153
2154 delete[] matrix;
2155
2156 return true;
2157}
2158
2159bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
2160{
2161 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2162
2163 for (int i = 0; i < count; i++)
2164 {
2165 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
2166 value[1], value[4], value[7], 0,
2167 value[2], value[5], value[8], 0,
2168 0, 0, 0, 1);
2169
2170 value += 9;
2171 }
2172
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002173 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2174
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002175 D3DXHANDLE constantPS;
2176 D3DXHANDLE constantVS;
2177 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002178 IDirect3DDevice9 *device = getDevice();
2179
2180 if (constantPS)
2181 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002182 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002183 }
2184
2185 if (constantVS)
2186 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002187 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002188 }
2189
2190 delete[] matrix;
2191
2192 return true;
2193}
2194
2195bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
2196{
2197 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2198
2199 for (int i = 0; i < count; i++)
2200 {
2201 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
2202 value[1], value[5], value[9], value[13],
2203 value[2], value[6], value[10], value[14],
2204 value[3], value[7], value[11], value[15]);
2205
2206 value += 16;
2207 }
2208
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002209 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2210
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002211 D3DXHANDLE constantPS;
2212 D3DXHANDLE constantVS;
2213 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002214 IDirect3DDevice9 *device = getDevice();
2215
2216 if (constantPS)
2217 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002218 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002219 }
2220
2221 if (constantVS)
2222 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002223 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002224 }
2225
2226 delete[] matrix;
2227
2228 return true;
2229}
2230
2231bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
2232{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002233 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2234
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002235 D3DXHANDLE constantPS;
2236 D3DXHANDLE constantVS;
2237 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002238 IDirect3DDevice9 *device = getDevice();
2239
2240 if (constantPS)
2241 {
2242 D3DXCONSTANT_DESC constantDescription;
2243 UINT descriptionCount = 1;
2244 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
2245
daniel@transgaming.com2884b782010-03-08 21:30:48 +00002246 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002247 {
2248 return false;
2249 }
2250
2251 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2252 {
2253 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
2254
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002255 for (int i = 0; i < count; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002256 {
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002257 unsigned int samplerIndex = firstIndex + i;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002258
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002259 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002260 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002261 ASSERT(mSamplers[samplerIndex].active);
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002262 mSamplers[samplerIndex].logicalTextureUnit = v[i];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002263 }
2264 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002265
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002266 return true;
2267 }
2268 }
2269
2270 if (constantPS)
2271 {
2272 mConstantTablePS->SetIntArray(device, constantPS, v, count);
2273 }
2274
2275 if (constantVS)
2276 {
2277 mConstantTableVS->SetIntArray(device, constantVS, v, count);
2278 }
2279
2280 return true;
2281}
2282
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002283bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
2284{
2285 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2286
2287 for (int i = 0; i < count; i++)
2288 {
2289 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2290
2291 v += 2;
2292 }
2293
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002294 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2295
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002296 D3DXHANDLE constantPS;
2297 D3DXHANDLE constantVS;
2298 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002299 IDirect3DDevice9 *device = getDevice();
2300
2301 if (constantPS)
2302 {
2303 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2304 }
2305
2306 if (constantVS)
2307 {
2308 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2309 }
2310
2311 delete[] vector;
2312
2313 return true;
2314}
2315
2316bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
2317{
2318 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2319
2320 for (int i = 0; i < count; i++)
2321 {
2322 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2323
2324 v += 3;
2325 }
2326
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002327 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2328
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002329 D3DXHANDLE constantPS;
2330 D3DXHANDLE constantVS;
2331 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002332 IDirect3DDevice9 *device = getDevice();
2333
2334 if (constantPS)
2335 {
2336 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2337 }
2338
2339 if (constantVS)
2340 {
2341 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2342 }
2343
2344 delete[] vector;
2345
2346 return true;
2347}
2348
2349bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
2350{
2351 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2352
2353 for (int i = 0; i < count; i++)
2354 {
2355 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2356
2357 v += 4;
2358 }
2359
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002360 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2361
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002362 D3DXHANDLE constantPS;
2363 D3DXHANDLE constantVS;
2364 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002365 IDirect3DDevice9 *device = getDevice();
2366
2367 if (constantPS)
2368 {
2369 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2370 }
2371
2372 if (constantVS)
2373 {
2374 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2375 }
2376
2377 delete [] vector;
2378
2379 return true;
2380}
2381
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002382void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002383{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002384 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002385 {
2386 return;
2387 }
2388
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002389 char info[1024];
2390
2391 va_list vararg;
2392 va_start(vararg, format);
2393 vsnprintf(info, sizeof(info), format, vararg);
2394 va_end(vararg);
2395
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002396 size_t infoLength = strlen(info);
2397
2398 if (!mInfoLog)
2399 {
2400 mInfoLog = new char[infoLength + 1];
2401 strcpy(mInfoLog, info);
2402 }
2403 else
2404 {
2405 size_t logLength = strlen(mInfoLog);
2406 char *newLog = new char[logLength + infoLength + 1];
2407 strcpy(newLog, mInfoLog);
2408 strcpy(newLog + logLength, info);
2409
2410 delete[] mInfoLog;
2411 mInfoLog = newLog;
2412 }
2413}
2414
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002415void Program::resetInfoLog()
2416{
2417 if (mInfoLog)
2418 {
2419 delete [] mInfoLog;
daniel@transgaming.com6a20d102010-08-31 13:54:27 +00002420 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002421 }
2422}
2423
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002424// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
2425void Program::unlink(bool destroy)
2426{
2427 if (destroy) // Object being destructed
2428 {
2429 if (mFragmentShader)
2430 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002431 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002432 mFragmentShader = NULL;
2433 }
2434
2435 if (mVertexShader)
2436 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002437 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002438 mVertexShader = NULL;
2439 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002440 }
2441
2442 if (mPixelExecutable)
2443 {
2444 mPixelExecutable->Release();
2445 mPixelExecutable = NULL;
2446 }
2447
2448 if (mVertexExecutable)
2449 {
2450 mVertexExecutable->Release();
2451 mVertexExecutable = NULL;
2452 }
2453
2454 if (mConstantTablePS)
2455 {
2456 mConstantTablePS->Release();
2457 mConstantTablePS = NULL;
2458 }
2459
2460 if (mConstantTableVS)
2461 {
2462 mConstantTableVS->Release();
2463 mConstantTableVS = NULL;
2464 }
2465
2466 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2467 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002468 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002469 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002470 }
2471
2472 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2473 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00002474 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002475 }
2476
2477 while (!mUniforms.empty())
2478 {
2479 delete mUniforms.back();
2480 mUniforms.pop_back();
2481 }
2482
daniel@transgaming.com31754962010-11-28 02:02:52 +00002483 mDxDepthRangeLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002484 mDxDepthLocation = -1;
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002485 mDxViewportLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002486 mDxHalfPixelSizeLocation = -1;
2487 mDxFrontCCWLocation = -1;
2488 mDxPointsOrLinesLocation = -1;
2489
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002490 mUniformIndex.clear();
2491
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002492 mPixelHLSL.clear();
2493 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002494
2495 delete[] mInfoLog;
2496 mInfoLog = NULL;
2497
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002498 mLinked = false;
2499}
2500
2501bool Program::isLinked()
2502{
2503 return mLinked;
2504}
2505
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002506bool Program::isValidated() const
2507{
2508 return mValidated;
2509}
2510
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002511void Program::release()
2512{
2513 mRefCount--;
2514
2515 if (mRefCount == 0 && mDeleteStatus)
2516 {
2517 mResourceManager->deleteProgram(mHandle);
2518 }
2519}
2520
2521void Program::addRef()
2522{
2523 mRefCount++;
2524}
2525
2526unsigned int Program::getRefCount() const
2527{
2528 return mRefCount;
2529}
2530
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002531unsigned int Program::getSerial() const
2532{
2533 return mSerial;
2534}
2535
2536unsigned int Program::issueSerial()
2537{
2538 return mCurrentSerial++;
2539}
2540
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002541int Program::getInfoLogLength() const
2542{
2543 if (!mInfoLog)
2544 {
2545 return 0;
2546 }
2547 else
2548 {
2549 return strlen(mInfoLog) + 1;
2550 }
2551}
2552
2553void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2554{
2555 int index = 0;
2556
2557 if (mInfoLog)
2558 {
2559 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2560 {
2561 infoLog[index] = mInfoLog[index];
2562 index++;
2563 }
2564 }
2565
2566 if (bufSize)
2567 {
2568 infoLog[index] = '\0';
2569 }
2570
2571 if (length)
2572 {
2573 *length = index;
2574 }
2575}
2576
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002577void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2578{
2579 int total = 0;
2580
2581 if (mVertexShader)
2582 {
2583 if (total < maxCount)
2584 {
2585 shaders[total] = mVertexShader->getHandle();
2586 }
2587
2588 total++;
2589 }
2590
2591 if (mFragmentShader)
2592 {
2593 if (total < maxCount)
2594 {
2595 shaders[total] = mFragmentShader->getHandle();
2596 }
2597
2598 total++;
2599 }
2600
2601 if (count)
2602 {
2603 *count = total;
2604 }
2605}
2606
daniel@transgaming.com85423182010-04-22 13:35:27 +00002607void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2608{
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002609 // Skip over inactive attributes
2610 unsigned int activeAttribute = 0;
2611 unsigned int attribute;
2612 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
daniel@transgaming.com85423182010-04-22 13:35:27 +00002613 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002614 if (mLinkedAttribute[attribute].name.empty())
daniel@transgaming.com85423182010-04-22 13:35:27 +00002615 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002616 continue;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002617 }
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002618
2619 if (activeAttribute == index)
2620 {
2621 break;
2622 }
2623
2624 activeAttribute++;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002625 }
2626
2627 if (bufsize > 0)
2628 {
2629 const char *string = mLinkedAttribute[attribute].name.c_str();
2630
2631 strncpy(name, string, bufsize);
2632 name[bufsize - 1] = '\0';
2633
2634 if (length)
2635 {
2636 *length = strlen(name);
2637 }
2638 }
2639
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002640 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002641
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002642 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002643}
2644
2645GLint Program::getActiveAttributeCount()
2646{
2647 int count = 0;
2648
2649 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2650 {
2651 if (!mLinkedAttribute[attributeIndex].name.empty())
2652 {
2653 count++;
2654 }
2655 }
2656
2657 return count;
2658}
2659
2660GLint Program::getActiveAttributeMaxLength()
2661{
2662 int maxLength = 0;
2663
2664 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2665 {
2666 if (!mLinkedAttribute[attributeIndex].name.empty())
2667 {
2668 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2669 }
2670 }
2671
2672 return maxLength;
2673}
2674
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002675void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2676{
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002677 // Skip over internal uniforms
2678 unsigned int activeUniform = 0;
2679 unsigned int uniform;
2680 for (uniform = 0; uniform < mUniforms.size(); uniform++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002681 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002682 if (mUniforms[uniform]->name.substr(0, 3) == "dx_")
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002683 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002684 continue;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002685 }
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002686
2687 if (activeUniform == index)
2688 {
2689 break;
2690 }
2691
2692 activeUniform++;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002693 }
2694
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002695 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2696
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002697 if (bufsize > 0)
2698 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002699 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002700
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002701 if (mUniforms[uniform]->arraySize != 1)
2702 {
2703 string += "[0]";
2704 }
2705
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002706 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002707 name[bufsize - 1] = '\0';
2708
2709 if (length)
2710 {
2711 *length = strlen(name);
2712 }
2713 }
2714
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002715 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002716
2717 *type = mUniforms[uniform]->type;
2718}
2719
2720GLint Program::getActiveUniformCount()
2721{
2722 int count = 0;
2723
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002724 unsigned int numUniforms = mUniforms.size();
2725 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002726 {
2727 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2728 {
2729 count++;
2730 }
2731 }
2732
2733 return count;
2734}
2735
2736GLint Program::getActiveUniformMaxLength()
2737{
2738 int maxLength = 0;
2739
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002740 unsigned int numUniforms = mUniforms.size();
2741 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002742 {
2743 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2744 {
zmo@google.com53d73e02011-03-24 21:27:57 +00002745 int length = (int)(undecorate(mUniforms[uniformIndex]->name).length() + 1);
zmo@google.com2a5645f2011-03-24 21:36:51 +00002746 if (mUniforms[uniformIndex]->arraySize != 1)
zmo@google.com53d73e02011-03-24 21:27:57 +00002747 {
2748 length += 3; // Counting in "[0]".
2749 }
2750 maxLength = std::max(length, maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002751 }
2752 }
2753
2754 return maxLength;
2755}
2756
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002757void Program::flagForDeletion()
2758{
2759 mDeleteStatus = true;
2760}
2761
2762bool Program::isFlaggedForDeletion() const
2763{
2764 return mDeleteStatus;
2765}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002766
2767void Program::validate()
2768{
2769 resetInfoLog();
2770
2771 if (!isLinked())
2772 {
2773 appendToInfoLog("Program has not been successfully linked.");
2774 mValidated = false;
2775 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002776 else
2777 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002778 applyUniforms();
2779 if (!validateSamplers())
2780 {
2781 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2782 mValidated = false;
2783 }
2784 else
2785 {
2786 mValidated = true;
2787 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002788 }
2789}
2790
2791bool Program::validateSamplers() const
2792{
2793 // if any two active samplers in a program are of different types, but refer to the same
2794 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2795 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2796 std::map<int, SamplerType> samplerMap;
2797 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2798 {
2799 if (mSamplers[i].active)
2800 {
2801 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2802 {
2803 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2804 return false;
2805 }
2806 else
2807 {
2808 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2809 }
2810 }
2811 }
2812
2813 return true;
2814}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002815
2816void Program::getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS)
2817{
2818 if (!targetUniform->handlesSet)
2819 {
2820 targetUniform->psHandle = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2821 targetUniform->vsHandle = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
2822 targetUniform->handlesSet = true;
2823 }
2824
2825 *constantPS = targetUniform->psHandle;
2826 *constantVS = targetUniform->vsHandle;
2827}
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002828
daniel@transgaming.com31754962010-11-28 02:02:52 +00002829GLint Program::getDxDepthRangeLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002830{
daniel@transgaming.com31754962010-11-28 02:02:52 +00002831 return mDxDepthRangeLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002832}
2833
2834GLint Program::getDxDepthLocation() const
2835{
2836 return mDxDepthLocation;
2837}
2838
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002839GLint Program::getDxViewportLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002840{
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002841 return mDxViewportLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002842}
2843
2844GLint Program::getDxHalfPixelSizeLocation() const
2845{
2846 return mDxHalfPixelSizeLocation;
2847}
2848
2849GLint Program::getDxFrontCCWLocation() const
2850{
2851 return mDxFrontCCWLocation;
2852}
2853
2854GLint Program::getDxPointsOrLinesLocation() const
2855{
2856 return mDxPointsOrLinesLocation;
2857}
2858
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002859}