blob: f2bc61ea82ddae60cf922729503c5d493d64a340 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010#include "libGLESv2/Program.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000011
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000012#include "common/debug.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000013
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000014#include "libGLESv2/main.h"
15#include "libGLESv2/Shader.h"
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000016#include "libGLESv2/utilities.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000017
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000018namespace gl
19{
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000020unsigned int Program::mCurrentSerial = 1;
21
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000022std::string str(int i)
23{
24 char buffer[20];
25 sprintf(buffer, "%d", i);
26 return buffer;
27}
28
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000029Uniform::Uniform(GLenum type, const std::string &name, unsigned int arraySize) : type(type), name(name), arraySize(arraySize)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000030{
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000031 int bytes = UniformTypeSize(type) * arraySize;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000032 data = new unsigned char[bytes];
33 memset(data, 0, bytes);
34 dirty = true;
daniel@transgaming.com2d84df02010-05-14 17:31:13 +000035 handlesSet = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000036}
37
38Uniform::~Uniform()
39{
40 delete[] data;
41}
42
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +000043UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
44 : name(name), element(element), index(index)
45{
46}
47
daniel@transgaming.com73a5db62010-10-15 17:58:13 +000048Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000049{
50 mFragmentShader = NULL;
51 mVertexShader = NULL;
52
53 mPixelExecutable = NULL;
54 mVertexExecutable = NULL;
55 mConstantTablePS = NULL;
56 mConstantTableVS = NULL;
57
daniel@transgaming.comcba50572010-03-28 19:36:09 +000058 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +000059 mValidated = false;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000060
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000061 unlink();
62
63 mDeleteStatus = false;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000064
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000065 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000066}
67
68Program::~Program()
69{
70 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000071
72 if (mVertexShader != NULL)
73 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000074 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000075 }
76
77 if (mFragmentShader != NULL)
78 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000079 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000080 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000081}
82
83bool Program::attachShader(Shader *shader)
84{
85 if (shader->getType() == GL_VERTEX_SHADER)
86 {
87 if (mVertexShader)
88 {
89 return false;
90 }
91
92 mVertexShader = (VertexShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000093 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000094 }
95 else if (shader->getType() == GL_FRAGMENT_SHADER)
96 {
97 if (mFragmentShader)
98 {
99 return false;
100 }
101
102 mFragmentShader = (FragmentShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000103 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000104 }
105 else UNREACHABLE();
106
107 return true;
108}
109
110bool Program::detachShader(Shader *shader)
111{
112 if (shader->getType() == GL_VERTEX_SHADER)
113 {
114 if (mVertexShader != shader)
115 {
116 return false;
117 }
118
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000119 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000120 mVertexShader = NULL;
121 }
122 else if (shader->getType() == GL_FRAGMENT_SHADER)
123 {
124 if (mFragmentShader != shader)
125 {
126 return false;
127 }
128
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000129 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000130 mFragmentShader = NULL;
131 }
132 else UNREACHABLE();
133
134 unlink();
135
136 return true;
137}
138
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000139int Program::getAttachedShadersCount() const
140{
141 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
142}
143
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144IDirect3DPixelShader9 *Program::getPixelShader()
145{
146 return mPixelExecutable;
147}
148
149IDirect3DVertexShader9 *Program::getVertexShader()
150{
151 return mVertexExecutable;
152}
153
154void Program::bindAttributeLocation(GLuint index, const char *name)
155{
156 if (index < MAX_VERTEX_ATTRIBS)
157 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000158 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
159 {
160 mAttributeBinding[i].erase(name);
161 }
162
163 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164 }
165}
166
167GLuint Program::getAttributeLocation(const char *name)
168{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000169 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000170 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000171 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000172 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000173 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000174 {
175 return index;
176 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177 }
178 }
179
180 return -1;
181}
182
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000183int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184{
185 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
186 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000187 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000188 }
189
190 return -1;
191}
192
193// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
194// index referenced in the compiled HLSL shader
195GLint Program::getSamplerMapping(unsigned int samplerIndex)
196{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000197 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
198
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000199 GLint logicalTextureUnit = -1;
200
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000201 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000202 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000203 logicalTextureUnit = mSamplers[samplerIndex].logicalTextureUnit;
204 }
205
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +0000206 if (logicalTextureUnit >= 0 && logicalTextureUnit < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000207 {
208 return logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000209 }
210
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000211 return -1;
212}
213
214SamplerType Program::getSamplerType(unsigned int samplerIndex)
215{
216 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
217 assert(mSamplers[samplerIndex].active);
218
219 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000220}
221
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000222bool Program::isSamplerDirty(unsigned int samplerIndex) const
223{
224 if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]))
225 {
226 return mSamplers[samplerIndex].dirty;
227 }
228 else UNREACHABLE();
229
230 return false;
231}
232
233void Program::setSamplerDirty(unsigned int samplerIndex, bool dirty)
234{
235 if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]))
236 {
237 mSamplers[samplerIndex].dirty = dirty;
238 }
239 else UNREACHABLE();
240}
241
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000242GLint Program::getUniformLocation(const char *name, bool decorated)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000243{
daniel@transgaming.comce864422010-11-18 13:16:49 +0000244 std::string _name = decorated ? name : decorate(name);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000245 int subscript = 0;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000246
daniel@transgaming.comce864422010-11-18 13:16:49 +0000247 // Strip any trailing array operator and retrieve the subscript
248 size_t open = _name.find_last_of('[');
249 size_t close = _name.find_last_of(']');
250 if (open != std::string::npos && close == _name.length() - 1)
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000251 {
daniel@transgaming.comce864422010-11-18 13:16:49 +0000252 subscript = atoi(_name.substr(open + 1).c_str());
253 _name.erase(open);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000254 }
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000255
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000256 unsigned int numUniforms = mUniformIndex.size();
257 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000258 {
daniel@transgaming.comce864422010-11-18 13:16:49 +0000259 if (mUniformIndex[location].name == _name &&
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000260 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000261 {
262 return location;
263 }
264 }
265
266 return -1;
267}
268
269bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
270{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000271 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000272 {
273 return false;
274 }
275
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000276 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000277 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000278
279 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000280 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000281 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000282
283 if (arraySize == 1 && count > 1)
284 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
285
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000286 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000287
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000288 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
289 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000290 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000291 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000292 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000293 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000294
295 if (arraySize == 1 && count > 1)
296 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000297
298 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000299 GLboolean *boolParams = new GLboolean[count];
300
301 for (int i = 0; i < count; ++i)
302 {
303 if (v[i] == 0.0f)
304 {
305 boolParams[i] = GL_FALSE;
306 }
307 else
308 {
309 boolParams[i] = GL_TRUE;
310 }
311 }
312
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000313 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
314 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000315
316 delete [] boolParams;
317 }
318 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000319 {
320 return false;
321 }
322
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000323 return true;
324}
325
326bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
327{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000328 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000329 {
330 return false;
331 }
332
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000333 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000334 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000335
336 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000337 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000338 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000339
340 if (arraySize == 1 && count > 1)
341 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
342
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000343 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000344
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000345 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
346 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000347 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000348 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000349 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000350 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000351
352 if (arraySize == 1 && count > 1)
353 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
354
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000355 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
356
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000357 GLboolean *boolParams = new GLboolean[count * 2];
358
359 for (int i = 0; i < count * 2; ++i)
360 {
361 if (v[i] == 0.0f)
362 {
363 boolParams[i] = GL_FALSE;
364 }
365 else
366 {
367 boolParams[i] = GL_TRUE;
368 }
369 }
370
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000371 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
372 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000373
374 delete [] boolParams;
375 }
376 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000377 {
378 return false;
379 }
380
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000381 return true;
382}
383
384bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
385{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000386 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000387 {
388 return false;
389 }
390
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000391 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000392 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000393
394 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000395 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000396 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000397
398 if (arraySize == 1 && count > 1)
399 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
400
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000401 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000402
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000403 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
404 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000405 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000406 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000407 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000408 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000409
410 if (arraySize == 1 && count > 1)
411 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
412
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000413 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000414 GLboolean *boolParams = new GLboolean[count * 3];
415
416 for (int i = 0; i < count * 3; ++i)
417 {
418 if (v[i] == 0.0f)
419 {
420 boolParams[i] = GL_FALSE;
421 }
422 else
423 {
424 boolParams[i] = GL_TRUE;
425 }
426 }
427
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000428 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
429 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000430
431 delete [] boolParams;
432 }
433 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000434 {
435 return false;
436 }
437
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000438 return true;
439}
440
441bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
442{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000443 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000444 {
445 return false;
446 }
447
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000448 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000449 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000450
451 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000452 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000453 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000454
455 if (arraySize == 1 && count > 1)
456 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
457
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000458 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000459
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000460 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
461 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000462 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000463 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000464 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000465 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000466
467 if (arraySize == 1 && count > 1)
468 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
469
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000470 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000471 GLboolean *boolParams = new GLboolean[count * 4];
472
473 for (int i = 0; i < count * 4; ++i)
474 {
475 if (v[i] == 0.0f)
476 {
477 boolParams[i] = GL_FALSE;
478 }
479 else
480 {
481 boolParams[i] = GL_TRUE;
482 }
483 }
484
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000485 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
486 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000487
488 delete [] boolParams;
489 }
490 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000491 {
492 return false;
493 }
494
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000495 return true;
496}
497
498bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
499{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000500 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000501 {
502 return false;
503 }
504
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000505 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000506 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000507
508 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000509 {
510 return false;
511 }
512
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000513 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000514
515 if (arraySize == 1 && count > 1)
516 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
517
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000518 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000519
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000520 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
521 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000522
523 return true;
524}
525
526bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
527{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000528 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000529 {
530 return false;
531 }
532
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000533 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000534 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000535
536 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000537 {
538 return false;
539 }
540
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000541 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000542
543 if (arraySize == 1 && count > 1)
544 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
545
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000546 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000547
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000548 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
549 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000550
551 return true;
552}
553
554bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
555{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000556 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000557 {
558 return false;
559 }
560
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000561 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000562 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000563
564 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000565 {
566 return false;
567 }
568
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000569 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000570
571 if (arraySize == 1 && count > 1)
572 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
573
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000574 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000575
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000576 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
577 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000578
579 return true;
580}
581
582bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
583{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000584 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000585 {
586 return false;
587 }
588
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000589 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000590 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000591
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000592 if (targetUniform->type == GL_INT ||
593 targetUniform->type == GL_SAMPLER_2D ||
594 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000595 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000596 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000597
598 if (arraySize == 1 && count > 1)
599 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
600
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000601 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000602
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000603 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
604 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000605 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000606 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000607 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000608 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000609
610 if (arraySize == 1 && count > 1)
611 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
612
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000613 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000614 GLboolean *boolParams = new GLboolean[count];
615
616 for (int i = 0; i < count; ++i)
617 {
618 if (v[i] == 0)
619 {
620 boolParams[i] = GL_FALSE;
621 }
622 else
623 {
624 boolParams[i] = GL_TRUE;
625 }
626 }
627
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000628 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
629 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000630
631 delete [] boolParams;
632 }
633 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000634 {
635 return false;
636 }
637
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000638 return true;
639}
640
641bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
642{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000643 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000644 {
645 return false;
646 }
647
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000648 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000649 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000650
651 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000652 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000653 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000654
655 if (arraySize == 1 && count > 1)
656 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
657
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000658 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000659
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000660 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
661 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000662 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000663 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000664 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000665 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000666
667 if (arraySize == 1 && count > 1)
668 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
669
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000670 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000671 GLboolean *boolParams = new GLboolean[count * 2];
672
673 for (int i = 0; i < count * 2; ++i)
674 {
675 if (v[i] == 0)
676 {
677 boolParams[i] = GL_FALSE;
678 }
679 else
680 {
681 boolParams[i] = GL_TRUE;
682 }
683 }
684
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000685 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
686 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000687
688 delete [] boolParams;
689 }
690 else
691 {
692 return false;
693 }
694
695 return true;
696}
697
698bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
699{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000700 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000701 {
702 return false;
703 }
704
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000705 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000706 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000707
708 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000709 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000710 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000711
712 if (arraySize == 1 && count > 1)
713 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
714
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000715 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000716
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000717 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
718 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000719 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000720 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000721 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000722 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000723
724 if (arraySize == 1 && count > 1)
725 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
726
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000727 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000728 GLboolean *boolParams = new GLboolean[count * 3];
729
730 for (int i = 0; i < count * 3; ++i)
731 {
732 if (v[i] == 0)
733 {
734 boolParams[i] = GL_FALSE;
735 }
736 else
737 {
738 boolParams[i] = GL_TRUE;
739 }
740 }
741
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000742 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
743 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000744
745 delete [] boolParams;
746 }
747 else
748 {
749 return false;
750 }
751
752 return true;
753}
754
755bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
756{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000757 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000758 {
759 return false;
760 }
761
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000762 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000763 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000764
765 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000766 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000767 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000768
769 if (arraySize == 1 && count > 1)
770 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
771
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000772 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000773
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000774 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
775 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000776 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000777 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000778 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000779 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000780
781 if (arraySize == 1 && count > 1)
782 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
783
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000784 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000785 GLboolean *boolParams = new GLboolean[count * 4];
786
787 for (int i = 0; i < count * 4; ++i)
788 {
789 if (v[i] == 0)
790 {
791 boolParams[i] = GL_FALSE;
792 }
793 else
794 {
795 boolParams[i] = GL_TRUE;
796 }
797 }
798
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000799 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
800 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000801
802 delete [] boolParams;
803 }
804 else
805 {
806 return false;
807 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000808
809 return true;
810}
811
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000812bool Program::getUniformfv(GLint location, GLfloat *params)
813{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000814 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000815 {
816 return false;
817 }
818
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000819 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000820
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000821 unsigned int count = UniformComponentCount(targetUniform->type);
822
823 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000824 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000825 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000826 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000827 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000828
829 for (unsigned int i = 0; i < count; ++i)
830 {
831 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
832 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000833 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000834 break;
835 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000836 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
837 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000838 break;
839 case GL_INT:
840 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000841 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000842
843 for (unsigned int i = 0; i < count; ++i)
844 {
845 params[i] = (float)intParams[i];
846 }
847 }
848 break;
849 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000850 }
851
852 return true;
853}
854
855bool Program::getUniformiv(GLint location, GLint *params)
856{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000857 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000858 {
859 return false;
860 }
861
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000862 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000863
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000864 unsigned int count = UniformComponentCount(targetUniform->type);
865
866 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000867 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000868 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000869 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000870 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000871
872 for (unsigned int i = 0; i < count; ++i)
873 {
874 params[i] = (GLint)boolParams[i];
875 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000876 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000877 break;
878 case GL_FLOAT:
879 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000880 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000881
882 for (unsigned int i = 0; i < count; ++i)
883 {
884 params[i] = (GLint)floatParams[i];
885 }
886 }
887 break;
888 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000889 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
890 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000891 break;
892 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000893 }
894
895 return true;
896}
897
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000898void Program::dirtyAllUniforms()
899{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000900 unsigned int numUniforms = mUniforms.size();
901 for (unsigned int index = 0; index < numUniforms; index++)
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000902 {
903 mUniforms[index]->dirty = true;
904 }
905}
906
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000907void Program::dirtyAllSamplers()
908{
909 for (unsigned int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; ++index)
910 {
911 mSamplers[index].dirty = true;
912 }
913}
914
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000915// Applies all the uniforms set for this program object to the Direct3D 9 device
916void Program::applyUniforms()
917{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000918 unsigned int numUniforms = mUniformIndex.size();
919 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000920 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000921 if (mUniformIndex[location].element != 0)
922 {
923 continue;
924 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000925
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000926 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
927
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000928 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000929 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000930 int arraySize = targetUniform->arraySize;
931 GLfloat *f = (GLfloat*)targetUniform->data;
932 GLint *i = (GLint*)targetUniform->data;
933 GLboolean *b = (GLboolean*)targetUniform->data;
934
935 switch (targetUniform->type)
936 {
937 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
938 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
939 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
940 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
941 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
942 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
943 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
944 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
945 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
946 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
947 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000948 case GL_SAMPLER_2D:
949 case GL_SAMPLER_CUBE:
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000950 case GL_INT: applyUniform1iv(location, arraySize, i); break;
951 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
952 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
953 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
954 default:
955 UNREACHABLE();
956 }
957
958 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000959 }
960 }
961}
962
963// Compiles the HLSL code of the attached shaders into executable binaries
964ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
965{
966 if (!hlsl)
967 {
968 return NULL;
969 }
970
971 ID3DXBuffer *binary = NULL;
972 ID3DXBuffer *errorMessage = NULL;
973
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000974 DWORD result;
975 if (perfActive())
976 {
977 DWORD flags = D3DXSHADER_DEBUG;
978#ifndef NDEBUG
979 flags |= D3DXSHADER_SKIPOPTIMIZATION;
980#endif
981
982 std::string sourcePath = getTempPath();
983 std::string sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
984 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
985
986 result = D3DXCompileShader(sourceText.c_str(), sourceText.size(), NULL, NULL, "main", profile, flags, &binary, &errorMessage, constantTable);
987 }
988 else
989 {
990 result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, NULL, "main", profile, 0, &binary, &errorMessage, constantTable);
991 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000992
993 if (SUCCEEDED(result))
994 {
995 return binary;
996 }
997
998 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
999 {
1000 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
1001 }
1002
1003 if (errorMessage)
1004 {
1005 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001006
daniel@transgaming.com0df16872010-05-12 16:51:08 +00001007 appendToInfoLog("%s\n", message);
daniel@transgaming.com0599dc62010-03-21 04:31:36 +00001008 TRACE("\n%s", hlsl);
1009 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001010 }
1011
1012 return NULL;
1013}
1014
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001015// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1016// Returns the number of used varying registers, or -1 if unsuccesful
1017int Program::packVaryings(const Varying *packing[][4])
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001018{
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001019 Context *context = getContext();
1020 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1021
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001022 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001023 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001024 int n = VariableRowCount(varying->type) * varying->size;
1025 int m = VariableColumnCount(varying->type);
1026 bool success = false;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001027
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001028 if (m == 2 || m == 3 || m == 4)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001029 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001030 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001031 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001032 bool available = true;
1033
1034 for (int y = 0; y < n && available; y++)
1035 {
1036 for (int x = 0; x < m && available; x++)
1037 {
1038 if (packing[r + y][x])
1039 {
1040 available = false;
1041 }
1042 }
1043 }
1044
1045 if (available)
1046 {
1047 varying->reg = r;
1048 varying->col = 0;
1049
1050 for (int y = 0; y < n; y++)
1051 {
1052 for (int x = 0; x < m; x++)
1053 {
1054 packing[r + y][x] = &*varying;
1055 }
1056 }
1057
1058 success = true;
1059 }
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001060 }
1061
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001062 if (!success && m == 2)
1063 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001064 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001065 {
1066 bool available = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001067
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001068 for (int y = 0; y < n && available; y++)
1069 {
1070 for (int x = 2; x < 4 && available; x++)
1071 {
1072 if (packing[r + y][x])
1073 {
1074 available = false;
1075 }
1076 }
1077 }
1078
1079 if (available)
1080 {
1081 varying->reg = r;
1082 varying->col = 2;
1083
1084 for (int y = 0; y < n; y++)
1085 {
1086 for (int x = 2; x < 4; x++)
1087 {
1088 packing[r + y][x] = &*varying;
1089 }
1090 }
1091
1092 success = true;
1093 }
1094 }
1095 }
1096 }
1097 else if (m == 1)
1098 {
1099 int space[4] = {0};
1100
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001101 for (int y = 0; y < maxVaryingVectors; y++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001102 {
1103 for (int x = 0; x < 4; x++)
1104 {
1105 space[x] += packing[y][x] ? 0 : 1;
1106 }
1107 }
1108
1109 int column = 0;
1110
1111 for (int x = 0; x < 4; x++)
1112 {
1113 if (space[x] > n && space[x] < space[column])
1114 {
1115 column = x;
1116 }
1117 }
1118
1119 if (space[column] > n)
1120 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001121 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001122 {
1123 if (!packing[r][column])
1124 {
1125 varying->reg = r;
1126
1127 for (int y = r; y < r + n; y++)
1128 {
1129 packing[y][column] = &*varying;
1130 }
1131
1132 break;
1133 }
1134 }
1135
1136 varying->col = column;
1137
1138 success = true;
1139 }
1140 }
1141 else UNREACHABLE();
1142
1143 if (!success)
1144 {
1145 appendToInfoLog("Could not pack varying %s", varying->name.c_str());
1146
1147 return -1;
1148 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001149 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001150
1151 // Return the number of used registers
1152 int registers = 0;
1153
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001154 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001155 {
1156 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1157 {
1158 registers++;
1159 }
1160 }
1161
1162 return registers;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001163}
1164
1165bool Program::linkVaryings()
1166{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001167 if (mPixelHLSL.empty() || mVertexHLSL.empty())
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001168 {
1169 return false;
1170 }
1171
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001172 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001173 int registers = packVaryings(packing);
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001174
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001175 if (registers < 0)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001176 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001177 return false;
1178 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001179
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001180 Context *context = getContext();
1181 const bool sm3 = context->supportsShaderModel3();
1182 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1183
1184 if (registers == maxVaryingVectors && mFragmentShader->mUsesFragCoord)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001185 {
1186 appendToInfoLog("No varying registers left to support gl_FragCoord");
1187
1188 return false;
1189 }
1190
1191 for (VaryingList::iterator input = mFragmentShader->varyings.begin(); input != mFragmentShader->varyings.end(); input++)
1192 {
1193 bool matched = false;
1194
1195 for (VaryingList::iterator output = mVertexShader->varyings.begin(); output != mVertexShader->varyings.end(); output++)
1196 {
1197 if (output->name == input->name)
1198 {
1199 if (output->type != input->type || output->size != input->size)
1200 {
1201 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
1202
1203 return false;
1204 }
1205
1206 output->reg = input->reg;
1207 output->col = input->col;
1208
1209 matched = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001210 break;
1211 }
1212 }
1213
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001214 if (!matched)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001215 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001216 appendToInfoLog("Fragment varying varying %s does not match any vertex varying", input->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001217
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001218 return false;
1219 }
1220 }
1221
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001222 std::string varyingSemantic = (sm3 ? "COLOR" : "TEXCOORD");
1223
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001224 mVertexHLSL += "struct VS_INPUT\n"
1225 "{\n";
1226
1227 int semanticIndex = 0;
1228 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1229 {
1230 switch (attribute->type)
1231 {
1232 case GL_FLOAT: mVertexHLSL += " float "; break;
1233 case GL_FLOAT_VEC2: mVertexHLSL += " float2 "; break;
1234 case GL_FLOAT_VEC3: mVertexHLSL += " float3 "; break;
1235 case GL_FLOAT_VEC4: mVertexHLSL += " float4 "; break;
1236 case GL_FLOAT_MAT2: mVertexHLSL += " float2x2 "; break;
1237 case GL_FLOAT_MAT3: mVertexHLSL += " float3x3 "; break;
1238 case GL_FLOAT_MAT4: mVertexHLSL += " float4x4 "; break;
1239 default: UNREACHABLE();
1240 }
1241
1242 mVertexHLSL += decorate(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1243
1244 semanticIndex += VariableRowCount(attribute->type);
1245 }
1246
1247 mVertexHLSL += "};\n"
1248 "\n"
1249 "struct VS_OUTPUT\n"
1250 "{\n"
1251 " float4 gl_Position : POSITION;\n";
1252
1253 for (int r = 0; r < registers; r++)
1254 {
1255 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1256
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001257 mVertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001258 }
1259
1260 if (mFragmentShader->mUsesFragCoord)
1261 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001262 mVertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1263 }
1264
1265 if (mVertexShader->mUsesPointSize && sm3)
1266 {
1267 mVertexHLSL += " float gl_PointSize : PSIZE;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001268 }
1269
1270 mVertexHLSL += "};\n"
1271 "\n"
1272 "VS_OUTPUT main(VS_INPUT input)\n"
1273 "{\n";
1274
1275 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1276 {
1277 mVertexHLSL += " " + decorate(attribute->name) + " = ";
1278
1279 if (VariableRowCount(attribute->type) > 1) // Matrix
1280 {
1281 mVertexHLSL += "transpose";
1282 }
1283
1284 mVertexHLSL += "(input." + decorate(attribute->name) + ");\n";
1285 }
1286
1287 mVertexHLSL += "\n"
1288 " gl_main();\n"
1289 "\n"
1290 " VS_OUTPUT output;\n"
1291 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001292 " output.gl_Position.y = gl_Position.y - dx_HalfPixelSize.y * gl_Position.w;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001293 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1294 " output.gl_Position.w = gl_Position.w;\n";
1295
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001296 if (mVertexShader->mUsesPointSize && sm3)
1297 {
1298 mVertexHLSL += " output.gl_PointSize = clamp(gl_PointSize, 1.0, " + str((int)ALIASED_POINT_SIZE_RANGE_MAX_SM3) + ");\n";
1299 }
1300
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001301 if (mFragmentShader->mUsesFragCoord)
1302 {
1303 mVertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1304 }
1305
1306 for (VaryingList::iterator varying = mVertexShader->varyings.begin(); varying != mVertexShader->varyings.end(); varying++)
1307 {
1308 if (varying->reg >= 0)
1309 {
1310 for (int i = 0; i < varying->size; i++)
1311 {
1312 int rows = VariableRowCount(varying->type);
1313
1314 for (int j = 0; j < rows; j++)
1315 {
1316 int r = varying->reg + i * rows + j;
1317 mVertexHLSL += " output.v" + str(r);
1318
1319 bool sharedRegister = false; // Register used by multiple varyings
1320
1321 for (int x = 0; x < 4; x++)
1322 {
1323 if (packing[r][x] && packing[r][x] != packing[r][0])
1324 {
1325 sharedRegister = true;
1326 break;
1327 }
1328 }
1329
1330 if(sharedRegister)
1331 {
1332 mVertexHLSL += ".";
1333
1334 for (int x = 0; x < 4; x++)
1335 {
1336 if (packing[r][x] == &*varying)
1337 {
1338 switch(x)
1339 {
1340 case 0: mVertexHLSL += "x"; break;
1341 case 1: mVertexHLSL += "y"; break;
1342 case 2: mVertexHLSL += "z"; break;
1343 case 3: mVertexHLSL += "w"; break;
1344 }
1345 }
1346 }
1347 }
1348
1349 mVertexHLSL += " = " + varying->name;
1350
1351 if (varying->array)
1352 {
1353 mVertexHLSL += "[" + str(i) + "]";
1354 }
1355
1356 if (rows > 1)
1357 {
1358 mVertexHLSL += "[" + str(j) + "]";
1359 }
1360
1361 mVertexHLSL += ";\n";
1362 }
1363 }
1364 }
1365 }
1366
1367 mVertexHLSL += "\n"
1368 " return output;\n"
1369 "}\n";
1370
1371 mPixelHLSL += "struct PS_INPUT\n"
1372 "{\n";
1373
1374 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1375 {
1376 if (varying->reg >= 0)
1377 {
1378 for (int i = 0; i < varying->size; i++)
1379 {
1380 int rows = VariableRowCount(varying->type);
1381 for (int j = 0; j < rows; j++)
1382 {
1383 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001384 mPixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001385 }
1386 }
1387 }
1388 else UNREACHABLE();
1389 }
1390
1391 if (mFragmentShader->mUsesFragCoord)
1392 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001393 mPixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001394 if (sm3) {
daniel@transgaming.com996675c2010-11-17 13:06:29 +00001395 mPixelHLSL += " float2 dx_VPos : VPOS;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001396 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001397 }
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001398
1399 if (mFragmentShader->mUsesPointCoord && sm3)
1400 {
1401 mPixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1402 }
1403
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001404 if (mFragmentShader->mUsesFrontFacing)
1405 {
1406 mPixelHLSL += " float vFace : VFACE;\n";
1407 }
1408
1409 mPixelHLSL += "};\n"
1410 "\n"
1411 "struct PS_OUTPUT\n"
1412 "{\n"
1413 " float4 gl_Color[1] : COLOR;\n"
1414 "};\n"
1415 "\n"
1416 "PS_OUTPUT main(PS_INPUT input)\n"
1417 "{\n";
1418
1419 if (mFragmentShader->mUsesFragCoord)
1420 {
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001421 mPixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1422 if (sm3) {
1423 mPixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001424 " gl_FragCoord.y = 2.0 * dx_Viewport.y - input.dx_VPos.y;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001425 } else {
1426 mPixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Viewport.x + dx_Viewport.z;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001427 " gl_FragCoord.y = -(input.gl_FragCoord.y * rhw) * dx_Viewport.y + dx_Viewport.w;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001428 }
1429 mPixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001430 " gl_FragCoord.w = rhw;\n";
1431 }
1432
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001433 if (mFragmentShader->mUsesPointCoord && sm3)
1434 {
apatrick@chromium.orgda4d0492011-01-22 00:16:10 +00001435 mPixelHLSL += " gl_PointCoord = input.gl_PointCoord;\n";
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001436 }
1437
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001438 if (mFragmentShader->mUsesFrontFacing)
1439 {
1440 mPixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1441 }
1442
1443 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1444 {
1445 if (varying->reg >= 0)
1446 {
1447 for (int i = 0; i < varying->size; i++)
1448 {
1449 int rows = VariableRowCount(varying->type);
1450 for (int j = 0; j < rows; j++)
1451 {
1452 std::string n = str(varying->reg + i * rows + j);
1453 mPixelHLSL += " " + varying->name;
1454
1455 if (varying->array)
1456 {
1457 mPixelHLSL += "[" + str(i) + "]";
1458 }
1459
1460 if (rows > 1)
1461 {
1462 mPixelHLSL += "[" + str(j) + "]";
1463 }
1464
1465 mPixelHLSL += " = input.v" + n + ";\n";
1466 }
1467 }
1468 }
1469 else UNREACHABLE();
1470 }
1471
1472 mPixelHLSL += "\n"
1473 " gl_main();\n"
1474 "\n"
1475 " PS_OUTPUT output;\n"
1476 " output.gl_Color[0] = gl_Color[0];\n"
1477 "\n"
1478 " return output;\n"
1479 "}\n";
1480
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001481 return true;
1482}
1483
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001484// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1485// compiling them into binaries, determining the attribute mappings, and collecting
1486// a list of uniforms
1487void Program::link()
1488{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001489 unlink();
1490
1491 if (!mFragmentShader || !mFragmentShader->isCompiled())
1492 {
1493 return;
1494 }
1495
1496 if (!mVertexShader || !mVertexShader->isCompiled())
1497 {
1498 return;
1499 }
1500
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001501 mPixelHLSL = mFragmentShader->getHLSL();
1502 mVertexHLSL = mVertexShader->getHLSL();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001503
1504 if (!linkVaryings())
1505 {
1506 return;
1507 }
1508
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001509 Context *context = getContext();
1510 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1511 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1512
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001513 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1514 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001515
1516 if (vertexBinary && pixelBinary)
1517 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001518 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001519 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1520 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1521
1522 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1523 {
1524 return error(GL_OUT_OF_MEMORY);
1525 }
1526
1527 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001528
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001529 vertexBinary->Release();
1530 pixelBinary->Release();
1531 vertexBinary = NULL;
1532 pixelBinary = NULL;
1533
1534 if (mVertexExecutable && mPixelExecutable)
1535 {
1536 if (!linkAttributes())
1537 {
1538 return;
1539 }
1540
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001541 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001542 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001543 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001544 }
1545
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001546 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001547 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001548 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001549 }
1550
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001551 // these uniforms are searched as already-decorated because gl_ and dx_
1552 // are reserved prefixes, and do not receive additional decoration
daniel@transgaming.com31754962010-11-28 02:02:52 +00001553 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange", true);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001554 mDxDepthLocation = getUniformLocation("dx_Depth", true);
daniel@transgaming.com162267d2010-07-28 19:20:48 +00001555 mDxViewportLocation = getUniformLocation("dx_Viewport", true);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001556 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize", true);
1557 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW", true);
1558 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines", true);
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00001559
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001560 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001561 }
1562 }
1563}
1564
1565// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1566bool Program::linkAttributes()
1567{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001568 unsigned int usedLocations = 0;
1569
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001570 // Link attributes that have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001571 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001572 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001573 int location = getAttributeBinding(attribute->name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001574
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001575 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001576 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001577 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001578 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001579 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001580 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001581
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001582 mLinkedAttribute[location] = *attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001583
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001584 int rows = VariableRowCount(attribute->type);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001585
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001586 if (rows + location > MAX_VERTEX_ATTRIBS)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001587 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001588 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 +00001589
1590 return false;
1591 }
1592
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001593 for (int i = 0; i < rows; i++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001594 {
1595 usedLocations |= 1 << (location + i);
1596 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001597 }
1598 }
1599
1600 // Link attributes that don't have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001601 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001602 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001603 int location = getAttributeBinding(attribute->name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001604
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001605 if (location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001606 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001607 int rows = VariableRowCount(attribute->type);
1608 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001609
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001610 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001611 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001612 appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001613
1614 return false; // Fail to link
1615 }
1616
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001617 mLinkedAttribute[availableIndex] = *attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001618 }
1619 }
1620
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001621 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001622 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001623 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001624 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001625
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001626 for (int r = 0; r < rows; r++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001627 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001628 mSemanticIndex[attributeIndex++] = index++;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001629 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001630 }
1631
1632 return true;
1633}
1634
daniel@transgaming.com85423182010-04-22 13:35:27 +00001635int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001636{
1637 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1638 {
1639 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1640 {
1641 return location;
1642 }
1643 }
1644
1645 return -1;
1646}
1647
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001648bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1649{
1650 D3DXCONSTANTTABLE_DESC constantTableDescription;
1651 D3DXCONSTANT_DESC constantDescription;
1652 UINT descriptionCount = 1;
1653
1654 constantTable->GetDesc(&constantTableDescription);
1655
1656 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1657 {
1658 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1659 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1660
1661 if (!defineUniform(constantHandle, constantDescription))
1662 {
1663 return false;
1664 }
1665 }
1666
1667 return true;
1668}
1669
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001670// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001671// Returns true if succesful (uniform not already defined)
1672bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1673{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001674 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1675 {
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001676 for (unsigned int samplerIndex = constantDescription.RegisterIndex; samplerIndex < constantDescription.RegisterIndex + constantDescription.RegisterCount; samplerIndex++)
1677 {
1678 ASSERT(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001679
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001680 mSamplers[samplerIndex].active = true;
1681 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1682 mSamplers[samplerIndex].logicalTextureUnit = 0;
1683 mSamplers[samplerIndex].dirty = true;
1684 }
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001685 }
1686
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001687 switch(constantDescription.Class)
1688 {
1689 case D3DXPC_STRUCT:
1690 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001691 for (unsigned int arrayIndex = 0; arrayIndex < constantDescription.Elements; arrayIndex++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001692 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001693 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001694 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001695 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1696
1697 D3DXCONSTANT_DESC fieldDescription;
1698 UINT descriptionCount = 1;
1699
1700 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1701
1702 std::string structIndex = (constantDescription.Elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
1703
1704 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + structIndex + "."))
1705 {
1706 return false;
1707 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001708 }
1709 }
1710
1711 return true;
1712 }
1713 case D3DXPC_SCALAR:
1714 case D3DXPC_VECTOR:
1715 case D3DXPC_MATRIX_COLUMNS:
1716 case D3DXPC_OBJECT:
1717 return defineUniform(constantDescription, name + constantDescription.Name);
1718 default:
1719 UNREACHABLE();
1720 return false;
1721 }
1722}
1723
1724bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1725{
1726 Uniform *uniform = createUniform(constantDescription, name);
1727
1728 if(!uniform)
1729 {
1730 return false;
1731 }
1732
1733 // Check if already defined
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001734 GLint location = getUniformLocation(name.c_str(), true);
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001735 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001736
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001737 if (location >= 0)
1738 {
1739 delete uniform;
1740
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001741 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001742 {
1743 return false;
1744 }
1745 else
1746 {
1747 return true;
1748 }
1749 }
1750
1751 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001752 unsigned int uniformIndex = mUniforms.size() - 1;
1753
1754 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1755 {
1756 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1757 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001758
1759 return true;
1760}
1761
1762Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001763{
1764 if (constantDescription.Rows == 1) // Vectors and scalars
1765 {
1766 switch (constantDescription.Type)
1767 {
1768 case D3DXPT_SAMPLER2D:
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001769 switch (constantDescription.Columns)
1770 {
1771 case 1: return new Uniform(GL_SAMPLER_2D, name, constantDescription.Elements);
1772 default: UNREACHABLE();
1773 }
1774 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001775 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001776 switch (constantDescription.Columns)
1777 {
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001778 case 1: return new Uniform(GL_SAMPLER_CUBE, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001779 default: UNREACHABLE();
1780 }
1781 break;
1782 case D3DXPT_BOOL:
1783 switch (constantDescription.Columns)
1784 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001785 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1786 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1787 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1788 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001789 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001790 }
1791 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001792 case D3DXPT_INT:
1793 switch (constantDescription.Columns)
1794 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001795 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1796 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1797 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1798 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001799 default: UNREACHABLE();
1800 }
1801 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001802 case D3DXPT_FLOAT:
1803 switch (constantDescription.Columns)
1804 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001805 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1806 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1807 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1808 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001809 default: UNREACHABLE();
1810 }
1811 break;
1812 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001813 UNREACHABLE();
1814 }
1815 }
1816 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1817 {
1818 switch (constantDescription.Type)
1819 {
1820 case D3DXPT_FLOAT:
1821 switch (constantDescription.Rows)
1822 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001823 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1824 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1825 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001826 default: UNREACHABLE();
1827 }
1828 break;
1829 default: UNREACHABLE();
1830 }
1831 }
1832 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001833
1834 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001835}
1836
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001837// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001838std::string Program::decorate(const std::string &string)
1839{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001840 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001841 {
1842 return "_" + string;
1843 }
1844 else
1845 {
1846 return string;
1847 }
1848}
1849
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001850std::string Program::undecorate(const std::string &string)
1851{
1852 if (string.substr(0, 1) == "_")
1853 {
1854 return string.substr(1);
1855 }
1856 else
1857 {
1858 return string;
1859 }
1860}
1861
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001862bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1863{
1864 BOOL *vector = new BOOL[count];
1865 for (int i = 0; i < count; i++)
1866 {
1867 if (v[i] == GL_FALSE)
1868 vector[i] = 0;
1869 else
1870 vector[i] = 1;
1871 }
1872
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001873 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1874
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001875 D3DXHANDLE constantPS;
1876 D3DXHANDLE constantVS;
1877 getConstantHandles(targetUniform, &constantPS, &constantVS);
1878
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001879 IDirect3DDevice9 *device = getDevice();
1880
1881 if (constantPS)
1882 {
1883 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1884 }
1885
1886 if (constantVS)
1887 {
1888 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1889 }
1890
1891 delete [] vector;
1892
1893 return true;
1894}
1895
1896bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1897{
1898 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1899
1900 for (int i = 0; i < count; i++)
1901 {
1902 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1903 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1904
1905 v += 2;
1906 }
1907
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001908 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1909
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001910 D3DXHANDLE constantPS;
1911 D3DXHANDLE constantVS;
1912 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001913 IDirect3DDevice9 *device = getDevice();
1914
1915 if (constantPS)
1916 {
1917 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1918 }
1919
1920 if (constantVS)
1921 {
1922 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1923 }
1924
1925 delete[] vector;
1926
1927 return true;
1928}
1929
1930bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1931{
1932 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1933
1934 for (int i = 0; i < count; i++)
1935 {
1936 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1937 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1938 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1939
1940 v += 3;
1941 }
1942
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001943 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1944
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001945 D3DXHANDLE constantPS;
1946 D3DXHANDLE constantVS;
1947 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001948 IDirect3DDevice9 *device = getDevice();
1949
1950 if (constantPS)
1951 {
1952 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1953 }
1954
1955 if (constantVS)
1956 {
1957 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1958 }
1959
1960 delete[] vector;
1961
1962 return true;
1963}
1964
1965bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1966{
1967 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1968
1969 for (int i = 0; i < count; i++)
1970 {
1971 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1972 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1973 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1974 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1975
1976 v += 3;
1977 }
1978
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001979 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1980
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001981 D3DXHANDLE constantPS;
1982 D3DXHANDLE constantVS;
1983 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001984 IDirect3DDevice9 *device = getDevice();
1985
1986 if (constantPS)
1987 {
1988 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1989 }
1990
1991 if (constantVS)
1992 {
1993 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1994 }
1995
1996 delete [] vector;
1997
1998 return true;
1999}
2000
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002001bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
2002{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002003 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2004
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002005 D3DXHANDLE constantPS;
2006 D3DXHANDLE constantVS;
2007 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002008 IDirect3DDevice9 *device = getDevice();
2009
2010 if (constantPS)
2011 {
2012 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
2013 }
2014
2015 if (constantVS)
2016 {
2017 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
2018 }
2019
2020 return true;
2021}
2022
2023bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
2024{
2025 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2026
2027 for (int i = 0; i < count; i++)
2028 {
2029 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
2030
2031 v += 2;
2032 }
2033
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002034 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2035
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002036 D3DXHANDLE constantPS;
2037 D3DXHANDLE constantVS;
2038 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002039 IDirect3DDevice9 *device = getDevice();
2040
2041 if (constantPS)
2042 {
2043 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2044 }
2045
2046 if (constantVS)
2047 {
2048 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2049 }
2050
2051 delete[] vector;
2052
2053 return true;
2054}
2055
2056bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
2057{
2058 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2059
2060 for (int i = 0; i < count; i++)
2061 {
2062 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
2063
2064 v += 3;
2065 }
2066
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002067 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2068
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002069 D3DXHANDLE constantPS;
2070 D3DXHANDLE constantVS;
2071 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002072 IDirect3DDevice9 *device = getDevice();
2073
2074 if (constantPS)
2075 {
2076 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2077 }
2078
2079 if (constantVS)
2080 {
2081 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2082 }
2083
2084 delete[] vector;
2085
2086 return true;
2087}
2088
2089bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
2090{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002091 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2092
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002093 D3DXHANDLE constantPS;
2094 D3DXHANDLE constantVS;
2095 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002096 IDirect3DDevice9 *device = getDevice();
2097
2098 if (constantPS)
2099 {
2100 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
2101 }
2102
2103 if (constantVS)
2104 {
2105 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
2106 }
2107
2108 return true;
2109}
2110
2111bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
2112{
2113 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2114
2115 for (int i = 0; i < count; i++)
2116 {
2117 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
2118 value[1], value[3], 0, 0,
2119 0, 0, 1, 0,
2120 0, 0, 0, 1);
2121
2122 value += 4;
2123 }
2124
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002125 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2126
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002127 D3DXHANDLE constantPS;
2128 D3DXHANDLE constantVS;
2129 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002130 IDirect3DDevice9 *device = getDevice();
2131
2132 if (constantPS)
2133 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002134 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002135 }
2136
2137 if (constantVS)
2138 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002139 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002140 }
2141
2142 delete[] matrix;
2143
2144 return true;
2145}
2146
2147bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
2148{
2149 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2150
2151 for (int i = 0; i < count; i++)
2152 {
2153 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
2154 value[1], value[4], value[7], 0,
2155 value[2], value[5], value[8], 0,
2156 0, 0, 0, 1);
2157
2158 value += 9;
2159 }
2160
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002161 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2162
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002163 D3DXHANDLE constantPS;
2164 D3DXHANDLE constantVS;
2165 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002166 IDirect3DDevice9 *device = getDevice();
2167
2168 if (constantPS)
2169 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002170 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002171 }
2172
2173 if (constantVS)
2174 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002175 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002176 }
2177
2178 delete[] matrix;
2179
2180 return true;
2181}
2182
2183bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
2184{
2185 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2186
2187 for (int i = 0; i < count; i++)
2188 {
2189 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
2190 value[1], value[5], value[9], value[13],
2191 value[2], value[6], value[10], value[14],
2192 value[3], value[7], value[11], value[15]);
2193
2194 value += 16;
2195 }
2196
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002197 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2198
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002199 D3DXHANDLE constantPS;
2200 D3DXHANDLE constantVS;
2201 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002202 IDirect3DDevice9 *device = getDevice();
2203
2204 if (constantPS)
2205 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002206 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002207 }
2208
2209 if (constantVS)
2210 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002211 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002212 }
2213
2214 delete[] matrix;
2215
2216 return true;
2217}
2218
2219bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
2220{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002221 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2222
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002223 D3DXHANDLE constantPS;
2224 D3DXHANDLE constantVS;
2225 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002226 IDirect3DDevice9 *device = getDevice();
2227
2228 if (constantPS)
2229 {
2230 D3DXCONSTANT_DESC constantDescription;
2231 UINT descriptionCount = 1;
2232 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
2233
daniel@transgaming.com2884b782010-03-08 21:30:48 +00002234 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002235 {
2236 return false;
2237 }
2238
2239 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2240 {
2241 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
2242
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002243 for (int i = 0; i < count; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002244 {
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002245 unsigned int samplerIndex = firstIndex + i;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002246
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002247 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002248 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002249 ASSERT(mSamplers[samplerIndex].active);
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002250 mSamplers[samplerIndex].logicalTextureUnit = v[i];
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002251 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002252 }
2253 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002254
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002255 return true;
2256 }
2257 }
2258
2259 if (constantPS)
2260 {
2261 mConstantTablePS->SetIntArray(device, constantPS, v, count);
2262 }
2263
2264 if (constantVS)
2265 {
2266 mConstantTableVS->SetIntArray(device, constantVS, v, count);
2267 }
2268
2269 return true;
2270}
2271
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002272bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
2273{
2274 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2275
2276 for (int i = 0; i < count; i++)
2277 {
2278 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2279
2280 v += 2;
2281 }
2282
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002283 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2284
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002285 D3DXHANDLE constantPS;
2286 D3DXHANDLE constantVS;
2287 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002288 IDirect3DDevice9 *device = getDevice();
2289
2290 if (constantPS)
2291 {
2292 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2293 }
2294
2295 if (constantVS)
2296 {
2297 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2298 }
2299
2300 delete[] vector;
2301
2302 return true;
2303}
2304
2305bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
2306{
2307 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2308
2309 for (int i = 0; i < count; i++)
2310 {
2311 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2312
2313 v += 3;
2314 }
2315
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002316 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2317
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002318 D3DXHANDLE constantPS;
2319 D3DXHANDLE constantVS;
2320 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002321 IDirect3DDevice9 *device = getDevice();
2322
2323 if (constantPS)
2324 {
2325 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2326 }
2327
2328 if (constantVS)
2329 {
2330 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2331 }
2332
2333 delete[] vector;
2334
2335 return true;
2336}
2337
2338bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
2339{
2340 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2341
2342 for (int i = 0; i < count; i++)
2343 {
2344 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2345
2346 v += 4;
2347 }
2348
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002349 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2350
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002351 D3DXHANDLE constantPS;
2352 D3DXHANDLE constantVS;
2353 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002354 IDirect3DDevice9 *device = getDevice();
2355
2356 if (constantPS)
2357 {
2358 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2359 }
2360
2361 if (constantVS)
2362 {
2363 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2364 }
2365
2366 delete [] vector;
2367
2368 return true;
2369}
2370
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002371void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002372{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002373 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002374 {
2375 return;
2376 }
2377
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002378 char info[1024];
2379
2380 va_list vararg;
2381 va_start(vararg, format);
2382 vsnprintf(info, sizeof(info), format, vararg);
2383 va_end(vararg);
2384
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002385 size_t infoLength = strlen(info);
2386
2387 if (!mInfoLog)
2388 {
2389 mInfoLog = new char[infoLength + 1];
2390 strcpy(mInfoLog, info);
2391 }
2392 else
2393 {
2394 size_t logLength = strlen(mInfoLog);
2395 char *newLog = new char[logLength + infoLength + 1];
2396 strcpy(newLog, mInfoLog);
2397 strcpy(newLog + logLength, info);
2398
2399 delete[] mInfoLog;
2400 mInfoLog = newLog;
2401 }
2402}
2403
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002404void Program::resetInfoLog()
2405{
2406 if (mInfoLog)
2407 {
2408 delete [] mInfoLog;
daniel@transgaming.com6a20d102010-08-31 13:54:27 +00002409 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002410 }
2411}
2412
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002413// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
2414void Program::unlink(bool destroy)
2415{
2416 if (destroy) // Object being destructed
2417 {
2418 if (mFragmentShader)
2419 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002420 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002421 mFragmentShader = NULL;
2422 }
2423
2424 if (mVertexShader)
2425 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002426 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002427 mVertexShader = NULL;
2428 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002429 }
2430
2431 if (mPixelExecutable)
2432 {
2433 mPixelExecutable->Release();
2434 mPixelExecutable = NULL;
2435 }
2436
2437 if (mVertexExecutable)
2438 {
2439 mVertexExecutable->Release();
2440 mVertexExecutable = NULL;
2441 }
2442
2443 if (mConstantTablePS)
2444 {
2445 mConstantTablePS->Release();
2446 mConstantTablePS = NULL;
2447 }
2448
2449 if (mConstantTableVS)
2450 {
2451 mConstantTableVS->Release();
2452 mConstantTableVS = NULL;
2453 }
2454
2455 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2456 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002457 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002458 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002459 }
2460
2461 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2462 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00002463 mSamplers[index].active = false;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00002464 mSamplers[index].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002465 }
2466
2467 while (!mUniforms.empty())
2468 {
2469 delete mUniforms.back();
2470 mUniforms.pop_back();
2471 }
2472
daniel@transgaming.com31754962010-11-28 02:02:52 +00002473 mDxDepthRangeLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002474 mDxDepthLocation = -1;
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002475 mDxViewportLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002476 mDxHalfPixelSizeLocation = -1;
2477 mDxFrontCCWLocation = -1;
2478 mDxPointsOrLinesLocation = -1;
2479
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002480 mUniformIndex.clear();
2481
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002482 mPixelHLSL.clear();
2483 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002484
2485 delete[] mInfoLog;
2486 mInfoLog = NULL;
2487
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002488 mLinked = false;
2489}
2490
2491bool Program::isLinked()
2492{
2493 return mLinked;
2494}
2495
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002496bool Program::isValidated() const
2497{
2498 return mValidated;
2499}
2500
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002501void Program::release()
2502{
2503 mRefCount--;
2504
2505 if (mRefCount == 0 && mDeleteStatus)
2506 {
2507 mResourceManager->deleteProgram(mHandle);
2508 }
2509}
2510
2511void Program::addRef()
2512{
2513 mRefCount++;
2514}
2515
2516unsigned int Program::getRefCount() const
2517{
2518 return mRefCount;
2519}
2520
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002521unsigned int Program::getSerial() const
2522{
2523 return mSerial;
2524}
2525
2526unsigned int Program::issueSerial()
2527{
2528 return mCurrentSerial++;
2529}
2530
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002531int Program::getInfoLogLength() const
2532{
2533 if (!mInfoLog)
2534 {
2535 return 0;
2536 }
2537 else
2538 {
2539 return strlen(mInfoLog) + 1;
2540 }
2541}
2542
2543void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2544{
2545 int index = 0;
2546
2547 if (mInfoLog)
2548 {
2549 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2550 {
2551 infoLog[index] = mInfoLog[index];
2552 index++;
2553 }
2554 }
2555
2556 if (bufSize)
2557 {
2558 infoLog[index] = '\0';
2559 }
2560
2561 if (length)
2562 {
2563 *length = index;
2564 }
2565}
2566
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002567void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2568{
2569 int total = 0;
2570
2571 if (mVertexShader)
2572 {
2573 if (total < maxCount)
2574 {
2575 shaders[total] = mVertexShader->getHandle();
2576 }
2577
2578 total++;
2579 }
2580
2581 if (mFragmentShader)
2582 {
2583 if (total < maxCount)
2584 {
2585 shaders[total] = mFragmentShader->getHandle();
2586 }
2587
2588 total++;
2589 }
2590
2591 if (count)
2592 {
2593 *count = total;
2594 }
2595}
2596
daniel@transgaming.com85423182010-04-22 13:35:27 +00002597void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2598{
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002599 // Skip over inactive attributes
2600 unsigned int activeAttribute = 0;
2601 unsigned int attribute;
2602 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
daniel@transgaming.com85423182010-04-22 13:35:27 +00002603 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002604 if (mLinkedAttribute[attribute].name.empty())
daniel@transgaming.com85423182010-04-22 13:35:27 +00002605 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002606 continue;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002607 }
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002608
2609 if (activeAttribute == index)
2610 {
2611 break;
2612 }
2613
2614 activeAttribute++;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002615 }
2616
2617 if (bufsize > 0)
2618 {
2619 const char *string = mLinkedAttribute[attribute].name.c_str();
2620
2621 strncpy(name, string, bufsize);
2622 name[bufsize - 1] = '\0';
2623
2624 if (length)
2625 {
2626 *length = strlen(name);
2627 }
2628 }
2629
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002630 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002631
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002632 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002633}
2634
2635GLint Program::getActiveAttributeCount()
2636{
2637 int count = 0;
2638
2639 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2640 {
2641 if (!mLinkedAttribute[attributeIndex].name.empty())
2642 {
2643 count++;
2644 }
2645 }
2646
2647 return count;
2648}
2649
2650GLint Program::getActiveAttributeMaxLength()
2651{
2652 int maxLength = 0;
2653
2654 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2655 {
2656 if (!mLinkedAttribute[attributeIndex].name.empty())
2657 {
2658 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2659 }
2660 }
2661
2662 return maxLength;
2663}
2664
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002665void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2666{
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002667 // Skip over internal uniforms
2668 unsigned int activeUniform = 0;
2669 unsigned int uniform;
2670 for (uniform = 0; uniform < mUniforms.size(); uniform++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002671 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002672 if (mUniforms[uniform]->name.substr(0, 3) == "dx_")
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002673 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002674 continue;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002675 }
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002676
2677 if (activeUniform == index)
2678 {
2679 break;
2680 }
2681
2682 activeUniform++;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002683 }
2684
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002685 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2686
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002687 if (bufsize > 0)
2688 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002689 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002690
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002691 if (mUniforms[uniform]->arraySize != 1)
2692 {
2693 string += "[0]";
2694 }
2695
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002696 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002697 name[bufsize - 1] = '\0';
2698
2699 if (length)
2700 {
2701 *length = strlen(name);
2702 }
2703 }
2704
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002705 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002706
2707 *type = mUniforms[uniform]->type;
2708}
2709
2710GLint Program::getActiveUniformCount()
2711{
2712 int count = 0;
2713
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002714 unsigned int numUniforms = mUniforms.size();
2715 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002716 {
2717 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2718 {
2719 count++;
2720 }
2721 }
2722
2723 return count;
2724}
2725
2726GLint Program::getActiveUniformMaxLength()
2727{
2728 int maxLength = 0;
2729
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002730 unsigned int numUniforms = mUniforms.size();
2731 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002732 {
2733 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2734 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002735 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002736 }
2737 }
2738
2739 return maxLength;
2740}
2741
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002742void Program::flagForDeletion()
2743{
2744 mDeleteStatus = true;
2745}
2746
2747bool Program::isFlaggedForDeletion() const
2748{
2749 return mDeleteStatus;
2750}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002751
2752void Program::validate()
2753{
2754 resetInfoLog();
2755
2756 if (!isLinked())
2757 {
2758 appendToInfoLog("Program has not been successfully linked.");
2759 mValidated = false;
2760 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002761 else
2762 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002763 applyUniforms();
2764 if (!validateSamplers())
2765 {
2766 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2767 mValidated = false;
2768 }
2769 else
2770 {
2771 mValidated = true;
2772 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002773 }
2774}
2775
2776bool Program::validateSamplers() const
2777{
2778 // if any two active samplers in a program are of different types, but refer to the same
2779 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2780 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2781 std::map<int, SamplerType> samplerMap;
2782 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2783 {
2784 if (mSamplers[i].active)
2785 {
2786 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2787 {
2788 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2789 return false;
2790 }
2791 else
2792 {
2793 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2794 }
2795 }
2796 }
2797
2798 return true;
2799}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002800
2801void Program::getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS)
2802{
2803 if (!targetUniform->handlesSet)
2804 {
2805 targetUniform->psHandle = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2806 targetUniform->vsHandle = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
2807 targetUniform->handlesSet = true;
2808 }
2809
2810 *constantPS = targetUniform->psHandle;
2811 *constantVS = targetUniform->vsHandle;
2812}
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002813
daniel@transgaming.com31754962010-11-28 02:02:52 +00002814GLint Program::getDxDepthRangeLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002815{
daniel@transgaming.com31754962010-11-28 02:02:52 +00002816 return mDxDepthRangeLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002817}
2818
2819GLint Program::getDxDepthLocation() const
2820{
2821 return mDxDepthLocation;
2822}
2823
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002824GLint Program::getDxViewportLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002825{
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002826 return mDxViewportLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002827}
2828
2829GLint Program::getDxHalfPixelSizeLocation() const
2830{
2831 return mDxHalfPixelSizeLocation;
2832}
2833
2834GLint Program::getDxFrontCCWLocation() const
2835{
2836 return mDxFrontCCWLocation;
2837}
2838
2839GLint Program::getDxPointsOrLinesLocation() const
2840{
2841 return mDxPointsOrLinesLocation;
2842}
2843
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002844}