blob: e189eaa6be6588bbd9d00419c162cf218df71350 [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 {
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001113 if (space[x] >= n && space[x] < space[column])
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001114 {
1115 column = x;
1116 }
1117 }
1118
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001119 if (space[column] >= n)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001120 {
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.com97750022011-02-11 13:23:13 +00001172 // Reset the varying register assignments
1173 for (VaryingList::iterator fragVar = mFragmentShader->varyings.begin(); fragVar != mFragmentShader->varyings.end(); fragVar++)
1174 {
1175 fragVar->reg = -1;
1176 fragVar->col = -1;
1177 }
1178
1179 for (VaryingList::iterator vtxVar = mVertexShader->varyings.begin(); vtxVar != mVertexShader->varyings.end(); vtxVar++)
1180 {
1181 vtxVar->reg = -1;
1182 vtxVar->col = -1;
1183 }
1184
1185 // Map the varyings to the register file
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001186 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001187 int registers = packVaryings(packing);
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001188
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001189 if (registers < 0)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001190 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001191 return false;
1192 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001193
daniel@transgaming.com97750022011-02-11 13:23:13 +00001194 // Write the HLSL input/output declarations
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001195 Context *context = getContext();
1196 const bool sm3 = context->supportsShaderModel3();
1197 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1198
1199 if (registers == maxVaryingVectors && mFragmentShader->mUsesFragCoord)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001200 {
1201 appendToInfoLog("No varying registers left to support gl_FragCoord");
1202
1203 return false;
1204 }
1205
1206 for (VaryingList::iterator input = mFragmentShader->varyings.begin(); input != mFragmentShader->varyings.end(); input++)
1207 {
1208 bool matched = false;
1209
1210 for (VaryingList::iterator output = mVertexShader->varyings.begin(); output != mVertexShader->varyings.end(); output++)
1211 {
1212 if (output->name == input->name)
1213 {
1214 if (output->type != input->type || output->size != input->size)
1215 {
1216 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
1217
1218 return false;
1219 }
1220
1221 output->reg = input->reg;
1222 output->col = input->col;
1223
1224 matched = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001225 break;
1226 }
1227 }
1228
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001229 if (!matched)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001230 {
daniel@transgaming.com97750022011-02-11 13:23:13 +00001231 appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001232
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001233 return false;
1234 }
1235 }
1236
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001237 std::string varyingSemantic = (sm3 ? "COLOR" : "TEXCOORD");
1238
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001239 mVertexHLSL += "struct VS_INPUT\n"
1240 "{\n";
1241
1242 int semanticIndex = 0;
1243 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1244 {
1245 switch (attribute->type)
1246 {
1247 case GL_FLOAT: mVertexHLSL += " float "; break;
1248 case GL_FLOAT_VEC2: mVertexHLSL += " float2 "; break;
1249 case GL_FLOAT_VEC3: mVertexHLSL += " float3 "; break;
1250 case GL_FLOAT_VEC4: mVertexHLSL += " float4 "; break;
1251 case GL_FLOAT_MAT2: mVertexHLSL += " float2x2 "; break;
1252 case GL_FLOAT_MAT3: mVertexHLSL += " float3x3 "; break;
1253 case GL_FLOAT_MAT4: mVertexHLSL += " float4x4 "; break;
1254 default: UNREACHABLE();
1255 }
1256
1257 mVertexHLSL += decorate(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1258
1259 semanticIndex += VariableRowCount(attribute->type);
1260 }
1261
1262 mVertexHLSL += "};\n"
1263 "\n"
1264 "struct VS_OUTPUT\n"
1265 "{\n"
1266 " float4 gl_Position : POSITION;\n";
1267
1268 for (int r = 0; r < registers; r++)
1269 {
1270 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1271
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001272 mVertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001273 }
1274
1275 if (mFragmentShader->mUsesFragCoord)
1276 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001277 mVertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1278 }
1279
1280 if (mVertexShader->mUsesPointSize && sm3)
1281 {
1282 mVertexHLSL += " float gl_PointSize : PSIZE;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001283 }
1284
1285 mVertexHLSL += "};\n"
1286 "\n"
1287 "VS_OUTPUT main(VS_INPUT input)\n"
1288 "{\n";
1289
1290 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1291 {
1292 mVertexHLSL += " " + decorate(attribute->name) + " = ";
1293
1294 if (VariableRowCount(attribute->type) > 1) // Matrix
1295 {
1296 mVertexHLSL += "transpose";
1297 }
1298
1299 mVertexHLSL += "(input." + decorate(attribute->name) + ");\n";
1300 }
1301
1302 mVertexHLSL += "\n"
1303 " gl_main();\n"
1304 "\n"
1305 " VS_OUTPUT output;\n"
1306 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001307 " output.gl_Position.y = gl_Position.y - dx_HalfPixelSize.y * gl_Position.w;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001308 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1309 " output.gl_Position.w = gl_Position.w;\n";
1310
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001311 if (mVertexShader->mUsesPointSize && sm3)
1312 {
1313 mVertexHLSL += " output.gl_PointSize = clamp(gl_PointSize, 1.0, " + str((int)ALIASED_POINT_SIZE_RANGE_MAX_SM3) + ");\n";
1314 }
1315
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001316 if (mFragmentShader->mUsesFragCoord)
1317 {
1318 mVertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1319 }
1320
1321 for (VaryingList::iterator varying = mVertexShader->varyings.begin(); varying != mVertexShader->varyings.end(); varying++)
1322 {
1323 if (varying->reg >= 0)
1324 {
1325 for (int i = 0; i < varying->size; i++)
1326 {
1327 int rows = VariableRowCount(varying->type);
1328
1329 for (int j = 0; j < rows; j++)
1330 {
1331 int r = varying->reg + i * rows + j;
1332 mVertexHLSL += " output.v" + str(r);
1333
1334 bool sharedRegister = false; // Register used by multiple varyings
1335
1336 for (int x = 0; x < 4; x++)
1337 {
1338 if (packing[r][x] && packing[r][x] != packing[r][0])
1339 {
1340 sharedRegister = true;
1341 break;
1342 }
1343 }
1344
1345 if(sharedRegister)
1346 {
1347 mVertexHLSL += ".";
1348
1349 for (int x = 0; x < 4; x++)
1350 {
1351 if (packing[r][x] == &*varying)
1352 {
1353 switch(x)
1354 {
1355 case 0: mVertexHLSL += "x"; break;
1356 case 1: mVertexHLSL += "y"; break;
1357 case 2: mVertexHLSL += "z"; break;
1358 case 3: mVertexHLSL += "w"; break;
1359 }
1360 }
1361 }
1362 }
1363
1364 mVertexHLSL += " = " + varying->name;
1365
1366 if (varying->array)
1367 {
1368 mVertexHLSL += "[" + str(i) + "]";
1369 }
1370
1371 if (rows > 1)
1372 {
1373 mVertexHLSL += "[" + str(j) + "]";
1374 }
1375
1376 mVertexHLSL += ";\n";
1377 }
1378 }
1379 }
1380 }
1381
1382 mVertexHLSL += "\n"
1383 " return output;\n"
1384 "}\n";
1385
1386 mPixelHLSL += "struct PS_INPUT\n"
1387 "{\n";
1388
1389 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1390 {
1391 if (varying->reg >= 0)
1392 {
1393 for (int i = 0; i < varying->size; i++)
1394 {
1395 int rows = VariableRowCount(varying->type);
1396 for (int j = 0; j < rows; j++)
1397 {
1398 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001399 mPixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001400 }
1401 }
1402 }
1403 else UNREACHABLE();
1404 }
1405
1406 if (mFragmentShader->mUsesFragCoord)
1407 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001408 mPixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001409 if (sm3) {
daniel@transgaming.com996675c2010-11-17 13:06:29 +00001410 mPixelHLSL += " float2 dx_VPos : VPOS;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001411 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001412 }
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001413
1414 if (mFragmentShader->mUsesPointCoord && sm3)
1415 {
1416 mPixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1417 }
1418
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001419 if (mFragmentShader->mUsesFrontFacing)
1420 {
1421 mPixelHLSL += " float vFace : VFACE;\n";
1422 }
1423
1424 mPixelHLSL += "};\n"
1425 "\n"
1426 "struct PS_OUTPUT\n"
1427 "{\n"
1428 " float4 gl_Color[1] : COLOR;\n"
1429 "};\n"
1430 "\n"
1431 "PS_OUTPUT main(PS_INPUT input)\n"
1432 "{\n";
1433
1434 if (mFragmentShader->mUsesFragCoord)
1435 {
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001436 mPixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1437 if (sm3) {
1438 mPixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001439 " gl_FragCoord.y = 2.0 * dx_Viewport.y - input.dx_VPos.y;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001440 } else {
1441 mPixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Viewport.x + dx_Viewport.z;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001442 " gl_FragCoord.y = -(input.gl_FragCoord.y * rhw) * dx_Viewport.y + dx_Viewport.w;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001443 }
1444 mPixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001445 " gl_FragCoord.w = rhw;\n";
1446 }
1447
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001448 if (mFragmentShader->mUsesPointCoord && sm3)
1449 {
apatrick@chromium.orgda4d0492011-01-22 00:16:10 +00001450 mPixelHLSL += " gl_PointCoord = input.gl_PointCoord;\n";
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001451 }
1452
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001453 if (mFragmentShader->mUsesFrontFacing)
1454 {
1455 mPixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1456 }
1457
1458 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1459 {
1460 if (varying->reg >= 0)
1461 {
1462 for (int i = 0; i < varying->size; i++)
1463 {
1464 int rows = VariableRowCount(varying->type);
1465 for (int j = 0; j < rows; j++)
1466 {
1467 std::string n = str(varying->reg + i * rows + j);
1468 mPixelHLSL += " " + varying->name;
1469
1470 if (varying->array)
1471 {
1472 mPixelHLSL += "[" + str(i) + "]";
1473 }
1474
1475 if (rows > 1)
1476 {
1477 mPixelHLSL += "[" + str(j) + "]";
1478 }
1479
1480 mPixelHLSL += " = input.v" + n + ";\n";
1481 }
1482 }
1483 }
1484 else UNREACHABLE();
1485 }
1486
1487 mPixelHLSL += "\n"
1488 " gl_main();\n"
1489 "\n"
1490 " PS_OUTPUT output;\n"
1491 " output.gl_Color[0] = gl_Color[0];\n"
1492 "\n"
1493 " return output;\n"
1494 "}\n";
1495
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001496 return true;
1497}
1498
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001499// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1500// compiling them into binaries, determining the attribute mappings, and collecting
1501// a list of uniforms
1502void Program::link()
1503{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001504 unlink();
1505
1506 if (!mFragmentShader || !mFragmentShader->isCompiled())
1507 {
1508 return;
1509 }
1510
1511 if (!mVertexShader || !mVertexShader->isCompiled())
1512 {
1513 return;
1514 }
1515
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001516 mPixelHLSL = mFragmentShader->getHLSL();
1517 mVertexHLSL = mVertexShader->getHLSL();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001518
1519 if (!linkVaryings())
1520 {
1521 return;
1522 }
1523
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001524 Context *context = getContext();
1525 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1526 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1527
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001528 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1529 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001530
1531 if (vertexBinary && pixelBinary)
1532 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001533 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001534 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1535 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1536
1537 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1538 {
1539 return error(GL_OUT_OF_MEMORY);
1540 }
1541
1542 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001543
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001544 vertexBinary->Release();
1545 pixelBinary->Release();
1546 vertexBinary = NULL;
1547 pixelBinary = NULL;
1548
1549 if (mVertexExecutable && mPixelExecutable)
1550 {
1551 if (!linkAttributes())
1552 {
1553 return;
1554 }
1555
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001556 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001557 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001558 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001559 }
1560
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001561 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001562 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001563 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001564 }
1565
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001566 // these uniforms are searched as already-decorated because gl_ and dx_
1567 // are reserved prefixes, and do not receive additional decoration
daniel@transgaming.com31754962010-11-28 02:02:52 +00001568 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange", true);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001569 mDxDepthLocation = getUniformLocation("dx_Depth", true);
daniel@transgaming.com162267d2010-07-28 19:20:48 +00001570 mDxViewportLocation = getUniformLocation("dx_Viewport", true);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001571 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize", true);
1572 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW", true);
1573 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines", true);
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00001574
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001575 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001576 }
1577 }
1578}
1579
1580// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1581bool Program::linkAttributes()
1582{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001583 unsigned int usedLocations = 0;
1584
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001585 // Link attributes that have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001586 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001587 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001588 int location = getAttributeBinding(attribute->name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001589
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001590 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001591 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001592 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001593 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001594 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001595 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001596
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001597 mLinkedAttribute[location] = *attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001598
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001599 int rows = VariableRowCount(attribute->type);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001600
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001601 if (rows + location > MAX_VERTEX_ATTRIBS)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001602 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001603 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 +00001604
1605 return false;
1606 }
1607
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001608 for (int i = 0; i < rows; i++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001609 {
1610 usedLocations |= 1 << (location + i);
1611 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001612 }
1613 }
1614
1615 // Link attributes that don't have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001616 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001617 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001618 int location = getAttributeBinding(attribute->name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001619
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001620 if (location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001621 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001622 int rows = VariableRowCount(attribute->type);
1623 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001624
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001625 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001626 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001627 appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001628
1629 return false; // Fail to link
1630 }
1631
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001632 mLinkedAttribute[availableIndex] = *attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001633 }
1634 }
1635
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001636 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001637 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001638 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001639 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001640
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001641 for (int r = 0; r < rows; r++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001642 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001643 mSemanticIndex[attributeIndex++] = index++;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001644 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001645 }
1646
1647 return true;
1648}
1649
daniel@transgaming.com85423182010-04-22 13:35:27 +00001650int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001651{
1652 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1653 {
1654 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1655 {
1656 return location;
1657 }
1658 }
1659
1660 return -1;
1661}
1662
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001663bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1664{
1665 D3DXCONSTANTTABLE_DESC constantTableDescription;
1666 D3DXCONSTANT_DESC constantDescription;
1667 UINT descriptionCount = 1;
1668
1669 constantTable->GetDesc(&constantTableDescription);
1670
1671 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1672 {
1673 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1674 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1675
1676 if (!defineUniform(constantHandle, constantDescription))
1677 {
1678 return false;
1679 }
1680 }
1681
1682 return true;
1683}
1684
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001685// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001686// Returns true if succesful (uniform not already defined)
1687bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1688{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001689 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1690 {
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001691 for (unsigned int samplerIndex = constantDescription.RegisterIndex; samplerIndex < constantDescription.RegisterIndex + constantDescription.RegisterCount; samplerIndex++)
1692 {
1693 ASSERT(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001694
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001695 mSamplers[samplerIndex].active = true;
1696 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1697 mSamplers[samplerIndex].logicalTextureUnit = 0;
1698 mSamplers[samplerIndex].dirty = true;
1699 }
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001700 }
1701
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001702 switch(constantDescription.Class)
1703 {
1704 case D3DXPC_STRUCT:
1705 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001706 for (unsigned int arrayIndex = 0; arrayIndex < constantDescription.Elements; arrayIndex++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001707 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001708 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001709 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001710 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1711
1712 D3DXCONSTANT_DESC fieldDescription;
1713 UINT descriptionCount = 1;
1714
1715 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1716
1717 std::string structIndex = (constantDescription.Elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
1718
1719 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + structIndex + "."))
1720 {
1721 return false;
1722 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001723 }
1724 }
1725
1726 return true;
1727 }
1728 case D3DXPC_SCALAR:
1729 case D3DXPC_VECTOR:
1730 case D3DXPC_MATRIX_COLUMNS:
1731 case D3DXPC_OBJECT:
1732 return defineUniform(constantDescription, name + constantDescription.Name);
1733 default:
1734 UNREACHABLE();
1735 return false;
1736 }
1737}
1738
1739bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1740{
1741 Uniform *uniform = createUniform(constantDescription, name);
1742
1743 if(!uniform)
1744 {
1745 return false;
1746 }
1747
1748 // Check if already defined
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001749 GLint location = getUniformLocation(name.c_str(), true);
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001750 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001751
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001752 if (location >= 0)
1753 {
1754 delete uniform;
1755
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001756 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001757 {
1758 return false;
1759 }
1760 else
1761 {
1762 return true;
1763 }
1764 }
1765
1766 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001767 unsigned int uniformIndex = mUniforms.size() - 1;
1768
1769 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1770 {
1771 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1772 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001773
1774 return true;
1775}
1776
1777Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001778{
1779 if (constantDescription.Rows == 1) // Vectors and scalars
1780 {
1781 switch (constantDescription.Type)
1782 {
1783 case D3DXPT_SAMPLER2D:
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001784 switch (constantDescription.Columns)
1785 {
1786 case 1: return new Uniform(GL_SAMPLER_2D, name, constantDescription.Elements);
1787 default: UNREACHABLE();
1788 }
1789 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001790 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001791 switch (constantDescription.Columns)
1792 {
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001793 case 1: return new Uniform(GL_SAMPLER_CUBE, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001794 default: UNREACHABLE();
1795 }
1796 break;
1797 case D3DXPT_BOOL:
1798 switch (constantDescription.Columns)
1799 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001800 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1801 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1802 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1803 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001804 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001805 }
1806 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001807 case D3DXPT_INT:
1808 switch (constantDescription.Columns)
1809 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001810 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1811 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1812 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1813 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001814 default: UNREACHABLE();
1815 }
1816 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001817 case D3DXPT_FLOAT:
1818 switch (constantDescription.Columns)
1819 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001820 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1821 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1822 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1823 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001824 default: UNREACHABLE();
1825 }
1826 break;
1827 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001828 UNREACHABLE();
1829 }
1830 }
1831 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1832 {
1833 switch (constantDescription.Type)
1834 {
1835 case D3DXPT_FLOAT:
1836 switch (constantDescription.Rows)
1837 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001838 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1839 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1840 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001841 default: UNREACHABLE();
1842 }
1843 break;
1844 default: UNREACHABLE();
1845 }
1846 }
1847 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001848
1849 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001850}
1851
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001852// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001853std::string Program::decorate(const std::string &string)
1854{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001855 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001856 {
1857 return "_" + string;
1858 }
1859 else
1860 {
1861 return string;
1862 }
1863}
1864
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001865std::string Program::undecorate(const std::string &string)
1866{
1867 if (string.substr(0, 1) == "_")
1868 {
1869 return string.substr(1);
1870 }
1871 else
1872 {
1873 return string;
1874 }
1875}
1876
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001877bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1878{
1879 BOOL *vector = new BOOL[count];
1880 for (int i = 0; i < count; i++)
1881 {
1882 if (v[i] == GL_FALSE)
1883 vector[i] = 0;
1884 else
1885 vector[i] = 1;
1886 }
1887
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001888 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1889
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001890 D3DXHANDLE constantPS;
1891 D3DXHANDLE constantVS;
1892 getConstantHandles(targetUniform, &constantPS, &constantVS);
1893
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001894 IDirect3DDevice9 *device = getDevice();
1895
1896 if (constantPS)
1897 {
1898 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1899 }
1900
1901 if (constantVS)
1902 {
1903 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1904 }
1905
1906 delete [] vector;
1907
1908 return true;
1909}
1910
1911bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1912{
1913 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1914
1915 for (int i = 0; i < count; i++)
1916 {
1917 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1918 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1919
1920 v += 2;
1921 }
1922
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001923 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1924
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001925 D3DXHANDLE constantPS;
1926 D3DXHANDLE constantVS;
1927 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001928 IDirect3DDevice9 *device = getDevice();
1929
1930 if (constantPS)
1931 {
1932 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1933 }
1934
1935 if (constantVS)
1936 {
1937 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1938 }
1939
1940 delete[] vector;
1941
1942 return true;
1943}
1944
1945bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1946{
1947 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1948
1949 for (int i = 0; i < count; i++)
1950 {
1951 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1952 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1953 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1954
1955 v += 3;
1956 }
1957
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001958 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1959
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001960 D3DXHANDLE constantPS;
1961 D3DXHANDLE constantVS;
1962 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001963 IDirect3DDevice9 *device = getDevice();
1964
1965 if (constantPS)
1966 {
1967 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1968 }
1969
1970 if (constantVS)
1971 {
1972 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1973 }
1974
1975 delete[] vector;
1976
1977 return true;
1978}
1979
1980bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1981{
1982 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1983
1984 for (int i = 0; i < count; i++)
1985 {
1986 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1987 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1988 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1989 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1990
1991 v += 3;
1992 }
1993
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001994 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1995
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001996 D3DXHANDLE constantPS;
1997 D3DXHANDLE constantVS;
1998 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001999 IDirect3DDevice9 *device = getDevice();
2000
2001 if (constantPS)
2002 {
2003 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2004 }
2005
2006 if (constantVS)
2007 {
2008 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2009 }
2010
2011 delete [] vector;
2012
2013 return true;
2014}
2015
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002016bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
2017{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002018 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2019
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002020 D3DXHANDLE constantPS;
2021 D3DXHANDLE constantVS;
2022 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002023 IDirect3DDevice9 *device = getDevice();
2024
2025 if (constantPS)
2026 {
2027 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
2028 }
2029
2030 if (constantVS)
2031 {
2032 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
2033 }
2034
2035 return true;
2036}
2037
2038bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
2039{
2040 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2041
2042 for (int i = 0; i < count; i++)
2043 {
2044 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
2045
2046 v += 2;
2047 }
2048
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002049 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2050
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002051 D3DXHANDLE constantPS;
2052 D3DXHANDLE constantVS;
2053 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002054 IDirect3DDevice9 *device = getDevice();
2055
2056 if (constantPS)
2057 {
2058 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2059 }
2060
2061 if (constantVS)
2062 {
2063 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2064 }
2065
2066 delete[] vector;
2067
2068 return true;
2069}
2070
2071bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
2072{
2073 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2074
2075 for (int i = 0; i < count; i++)
2076 {
2077 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
2078
2079 v += 3;
2080 }
2081
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002082 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2083
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002084 D3DXHANDLE constantPS;
2085 D3DXHANDLE constantVS;
2086 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002087 IDirect3DDevice9 *device = getDevice();
2088
2089 if (constantPS)
2090 {
2091 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2092 }
2093
2094 if (constantVS)
2095 {
2096 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2097 }
2098
2099 delete[] vector;
2100
2101 return true;
2102}
2103
2104bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
2105{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002106 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2107
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002108 D3DXHANDLE constantPS;
2109 D3DXHANDLE constantVS;
2110 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002111 IDirect3DDevice9 *device = getDevice();
2112
2113 if (constantPS)
2114 {
2115 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
2116 }
2117
2118 if (constantVS)
2119 {
2120 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
2121 }
2122
2123 return true;
2124}
2125
2126bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
2127{
2128 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2129
2130 for (int i = 0; i < count; i++)
2131 {
2132 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
2133 value[1], value[3], 0, 0,
2134 0, 0, 1, 0,
2135 0, 0, 0, 1);
2136
2137 value += 4;
2138 }
2139
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002140 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2141
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002142 D3DXHANDLE constantPS;
2143 D3DXHANDLE constantVS;
2144 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002145 IDirect3DDevice9 *device = getDevice();
2146
2147 if (constantPS)
2148 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002149 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002150 }
2151
2152 if (constantVS)
2153 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002154 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002155 }
2156
2157 delete[] matrix;
2158
2159 return true;
2160}
2161
2162bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
2163{
2164 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2165
2166 for (int i = 0; i < count; i++)
2167 {
2168 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
2169 value[1], value[4], value[7], 0,
2170 value[2], value[5], value[8], 0,
2171 0, 0, 0, 1);
2172
2173 value += 9;
2174 }
2175
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002176 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2177
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002178 D3DXHANDLE constantPS;
2179 D3DXHANDLE constantVS;
2180 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002181 IDirect3DDevice9 *device = getDevice();
2182
2183 if (constantPS)
2184 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002185 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002186 }
2187
2188 if (constantVS)
2189 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002190 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002191 }
2192
2193 delete[] matrix;
2194
2195 return true;
2196}
2197
2198bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
2199{
2200 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2201
2202 for (int i = 0; i < count; i++)
2203 {
2204 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
2205 value[1], value[5], value[9], value[13],
2206 value[2], value[6], value[10], value[14],
2207 value[3], value[7], value[11], value[15]);
2208
2209 value += 16;
2210 }
2211
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002212 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2213
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002214 D3DXHANDLE constantPS;
2215 D3DXHANDLE constantVS;
2216 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002217 IDirect3DDevice9 *device = getDevice();
2218
2219 if (constantPS)
2220 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002221 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002222 }
2223
2224 if (constantVS)
2225 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002226 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002227 }
2228
2229 delete[] matrix;
2230
2231 return true;
2232}
2233
2234bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
2235{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002236 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2237
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002238 D3DXHANDLE constantPS;
2239 D3DXHANDLE constantVS;
2240 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002241 IDirect3DDevice9 *device = getDevice();
2242
2243 if (constantPS)
2244 {
2245 D3DXCONSTANT_DESC constantDescription;
2246 UINT descriptionCount = 1;
2247 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
2248
daniel@transgaming.com2884b782010-03-08 21:30:48 +00002249 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002250 {
2251 return false;
2252 }
2253
2254 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2255 {
2256 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
2257
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002258 for (int i = 0; i < count; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002259 {
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002260 unsigned int samplerIndex = firstIndex + i;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002261
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002262 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002263 {
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002264 ASSERT(mSamplers[samplerIndex].active);
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002265 mSamplers[samplerIndex].logicalTextureUnit = v[i];
daniel@transgaming.com4071e662010-05-12 16:51:16 +00002266 mSamplers[samplerIndex].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002267 }
2268 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002269
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002270 return true;
2271 }
2272 }
2273
2274 if (constantPS)
2275 {
2276 mConstantTablePS->SetIntArray(device, constantPS, v, count);
2277 }
2278
2279 if (constantVS)
2280 {
2281 mConstantTableVS->SetIntArray(device, constantVS, v, count);
2282 }
2283
2284 return true;
2285}
2286
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002287bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
2288{
2289 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2290
2291 for (int i = 0; i < count; i++)
2292 {
2293 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2294
2295 v += 2;
2296 }
2297
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002298 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2299
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002300 D3DXHANDLE constantPS;
2301 D3DXHANDLE constantVS;
2302 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002303 IDirect3DDevice9 *device = getDevice();
2304
2305 if (constantPS)
2306 {
2307 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2308 }
2309
2310 if (constantVS)
2311 {
2312 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2313 }
2314
2315 delete[] vector;
2316
2317 return true;
2318}
2319
2320bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
2321{
2322 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2323
2324 for (int i = 0; i < count; i++)
2325 {
2326 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2327
2328 v += 3;
2329 }
2330
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002331 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2332
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002333 D3DXHANDLE constantPS;
2334 D3DXHANDLE constantVS;
2335 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002336 IDirect3DDevice9 *device = getDevice();
2337
2338 if (constantPS)
2339 {
2340 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2341 }
2342
2343 if (constantVS)
2344 {
2345 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2346 }
2347
2348 delete[] vector;
2349
2350 return true;
2351}
2352
2353bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
2354{
2355 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2356
2357 for (int i = 0; i < count; i++)
2358 {
2359 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2360
2361 v += 4;
2362 }
2363
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002364 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2365
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002366 D3DXHANDLE constantPS;
2367 D3DXHANDLE constantVS;
2368 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002369 IDirect3DDevice9 *device = getDevice();
2370
2371 if (constantPS)
2372 {
2373 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2374 }
2375
2376 if (constantVS)
2377 {
2378 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2379 }
2380
2381 delete [] vector;
2382
2383 return true;
2384}
2385
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002386void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002387{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002388 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002389 {
2390 return;
2391 }
2392
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002393 char info[1024];
2394
2395 va_list vararg;
2396 va_start(vararg, format);
2397 vsnprintf(info, sizeof(info), format, vararg);
2398 va_end(vararg);
2399
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002400 size_t infoLength = strlen(info);
2401
2402 if (!mInfoLog)
2403 {
2404 mInfoLog = new char[infoLength + 1];
2405 strcpy(mInfoLog, info);
2406 }
2407 else
2408 {
2409 size_t logLength = strlen(mInfoLog);
2410 char *newLog = new char[logLength + infoLength + 1];
2411 strcpy(newLog, mInfoLog);
2412 strcpy(newLog + logLength, info);
2413
2414 delete[] mInfoLog;
2415 mInfoLog = newLog;
2416 }
2417}
2418
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002419void Program::resetInfoLog()
2420{
2421 if (mInfoLog)
2422 {
2423 delete [] mInfoLog;
daniel@transgaming.com6a20d102010-08-31 13:54:27 +00002424 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002425 }
2426}
2427
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002428// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
2429void Program::unlink(bool destroy)
2430{
2431 if (destroy) // Object being destructed
2432 {
2433 if (mFragmentShader)
2434 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002435 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002436 mFragmentShader = NULL;
2437 }
2438
2439 if (mVertexShader)
2440 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002441 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002442 mVertexShader = NULL;
2443 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002444 }
2445
2446 if (mPixelExecutable)
2447 {
2448 mPixelExecutable->Release();
2449 mPixelExecutable = NULL;
2450 }
2451
2452 if (mVertexExecutable)
2453 {
2454 mVertexExecutable->Release();
2455 mVertexExecutable = NULL;
2456 }
2457
2458 if (mConstantTablePS)
2459 {
2460 mConstantTablePS->Release();
2461 mConstantTablePS = NULL;
2462 }
2463
2464 if (mConstantTableVS)
2465 {
2466 mConstantTableVS->Release();
2467 mConstantTableVS = NULL;
2468 }
2469
2470 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2471 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002472 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002473 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002474 }
2475
2476 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2477 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00002478 mSamplers[index].active = false;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00002479 mSamplers[index].dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002480 }
2481
2482 while (!mUniforms.empty())
2483 {
2484 delete mUniforms.back();
2485 mUniforms.pop_back();
2486 }
2487
daniel@transgaming.com31754962010-11-28 02:02:52 +00002488 mDxDepthRangeLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002489 mDxDepthLocation = -1;
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002490 mDxViewportLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002491 mDxHalfPixelSizeLocation = -1;
2492 mDxFrontCCWLocation = -1;
2493 mDxPointsOrLinesLocation = -1;
2494
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002495 mUniformIndex.clear();
2496
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002497 mPixelHLSL.clear();
2498 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002499
2500 delete[] mInfoLog;
2501 mInfoLog = NULL;
2502
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002503 mLinked = false;
2504}
2505
2506bool Program::isLinked()
2507{
2508 return mLinked;
2509}
2510
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002511bool Program::isValidated() const
2512{
2513 return mValidated;
2514}
2515
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002516void Program::release()
2517{
2518 mRefCount--;
2519
2520 if (mRefCount == 0 && mDeleteStatus)
2521 {
2522 mResourceManager->deleteProgram(mHandle);
2523 }
2524}
2525
2526void Program::addRef()
2527{
2528 mRefCount++;
2529}
2530
2531unsigned int Program::getRefCount() const
2532{
2533 return mRefCount;
2534}
2535
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002536unsigned int Program::getSerial() const
2537{
2538 return mSerial;
2539}
2540
2541unsigned int Program::issueSerial()
2542{
2543 return mCurrentSerial++;
2544}
2545
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002546int Program::getInfoLogLength() const
2547{
2548 if (!mInfoLog)
2549 {
2550 return 0;
2551 }
2552 else
2553 {
2554 return strlen(mInfoLog) + 1;
2555 }
2556}
2557
2558void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2559{
2560 int index = 0;
2561
2562 if (mInfoLog)
2563 {
2564 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2565 {
2566 infoLog[index] = mInfoLog[index];
2567 index++;
2568 }
2569 }
2570
2571 if (bufSize)
2572 {
2573 infoLog[index] = '\0';
2574 }
2575
2576 if (length)
2577 {
2578 *length = index;
2579 }
2580}
2581
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002582void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2583{
2584 int total = 0;
2585
2586 if (mVertexShader)
2587 {
2588 if (total < maxCount)
2589 {
2590 shaders[total] = mVertexShader->getHandle();
2591 }
2592
2593 total++;
2594 }
2595
2596 if (mFragmentShader)
2597 {
2598 if (total < maxCount)
2599 {
2600 shaders[total] = mFragmentShader->getHandle();
2601 }
2602
2603 total++;
2604 }
2605
2606 if (count)
2607 {
2608 *count = total;
2609 }
2610}
2611
daniel@transgaming.com85423182010-04-22 13:35:27 +00002612void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2613{
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002614 // Skip over inactive attributes
2615 unsigned int activeAttribute = 0;
2616 unsigned int attribute;
2617 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
daniel@transgaming.com85423182010-04-22 13:35:27 +00002618 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002619 if (mLinkedAttribute[attribute].name.empty())
daniel@transgaming.com85423182010-04-22 13:35:27 +00002620 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002621 continue;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002622 }
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002623
2624 if (activeAttribute == index)
2625 {
2626 break;
2627 }
2628
2629 activeAttribute++;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002630 }
2631
2632 if (bufsize > 0)
2633 {
2634 const char *string = mLinkedAttribute[attribute].name.c_str();
2635
2636 strncpy(name, string, bufsize);
2637 name[bufsize - 1] = '\0';
2638
2639 if (length)
2640 {
2641 *length = strlen(name);
2642 }
2643 }
2644
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002645 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002646
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002647 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002648}
2649
2650GLint Program::getActiveAttributeCount()
2651{
2652 int count = 0;
2653
2654 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2655 {
2656 if (!mLinkedAttribute[attributeIndex].name.empty())
2657 {
2658 count++;
2659 }
2660 }
2661
2662 return count;
2663}
2664
2665GLint Program::getActiveAttributeMaxLength()
2666{
2667 int maxLength = 0;
2668
2669 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2670 {
2671 if (!mLinkedAttribute[attributeIndex].name.empty())
2672 {
2673 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2674 }
2675 }
2676
2677 return maxLength;
2678}
2679
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002680void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2681{
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002682 // Skip over internal uniforms
2683 unsigned int activeUniform = 0;
2684 unsigned int uniform;
2685 for (uniform = 0; uniform < mUniforms.size(); uniform++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002686 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002687 if (mUniforms[uniform]->name.substr(0, 3) == "dx_")
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002688 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002689 continue;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002690 }
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002691
2692 if (activeUniform == index)
2693 {
2694 break;
2695 }
2696
2697 activeUniform++;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002698 }
2699
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002700 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2701
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002702 if (bufsize > 0)
2703 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002704 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002705
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002706 if (mUniforms[uniform]->arraySize != 1)
2707 {
2708 string += "[0]";
2709 }
2710
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002711 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002712 name[bufsize - 1] = '\0';
2713
2714 if (length)
2715 {
2716 *length = strlen(name);
2717 }
2718 }
2719
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002720 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002721
2722 *type = mUniforms[uniform]->type;
2723}
2724
2725GLint Program::getActiveUniformCount()
2726{
2727 int count = 0;
2728
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002729 unsigned int numUniforms = mUniforms.size();
2730 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002731 {
2732 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2733 {
2734 count++;
2735 }
2736 }
2737
2738 return count;
2739}
2740
2741GLint Program::getActiveUniformMaxLength()
2742{
2743 int maxLength = 0;
2744
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002745 unsigned int numUniforms = mUniforms.size();
2746 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002747 {
2748 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2749 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002750 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002751 }
2752 }
2753
2754 return maxLength;
2755}
2756
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002757void Program::flagForDeletion()
2758{
2759 mDeleteStatus = true;
2760}
2761
2762bool Program::isFlaggedForDeletion() const
2763{
2764 return mDeleteStatus;
2765}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002766
2767void Program::validate()
2768{
2769 resetInfoLog();
2770
2771 if (!isLinked())
2772 {
2773 appendToInfoLog("Program has not been successfully linked.");
2774 mValidated = false;
2775 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002776 else
2777 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002778 applyUniforms();
2779 if (!validateSamplers())
2780 {
2781 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2782 mValidated = false;
2783 }
2784 else
2785 {
2786 mValidated = true;
2787 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002788 }
2789}
2790
2791bool Program::validateSamplers() const
2792{
2793 // if any two active samplers in a program are of different types, but refer to the same
2794 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2795 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2796 std::map<int, SamplerType> samplerMap;
2797 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2798 {
2799 if (mSamplers[i].active)
2800 {
2801 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2802 {
2803 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2804 return false;
2805 }
2806 else
2807 {
2808 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2809 }
2810 }
2811 }
2812
2813 return true;
2814}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002815
2816void Program::getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS)
2817{
2818 if (!targetUniform->handlesSet)
2819 {
2820 targetUniform->psHandle = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
2821 targetUniform->vsHandle = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
2822 targetUniform->handlesSet = true;
2823 }
2824
2825 *constantPS = targetUniform->psHandle;
2826 *constantVS = targetUniform->vsHandle;
2827}
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002828
daniel@transgaming.com31754962010-11-28 02:02:52 +00002829GLint Program::getDxDepthRangeLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002830{
daniel@transgaming.com31754962010-11-28 02:02:52 +00002831 return mDxDepthRangeLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002832}
2833
2834GLint Program::getDxDepthLocation() const
2835{
2836 return mDxDepthLocation;
2837}
2838
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002839GLint Program::getDxViewportLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002840{
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002841 return mDxViewportLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002842}
2843
2844GLint Program::getDxHalfPixelSizeLocation() const
2845{
2846 return mDxHalfPixelSizeLocation;
2847}
2848
2849GLint Program::getDxFrontCCWLocation() const
2850{
2851 return mDxFrontCCWLocation;
2852}
2853
2854GLint Program::getDxPointsOrLinesLocation() const
2855{
2856 return mDxPointsOrLinesLocation;
2857}
2858
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002859}