blob: 476999fcc5668f23cc12a346ef0401bf61054f9d [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
daniel@transgaming.com3f74c7a2011-05-11 15:36:51 +00002// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// 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.com87891f72011-06-01 15:28:35 +000018#include <string>
19
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +000020#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
21#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3
22#endif
23
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000024namespace gl
25{
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000026unsigned int Program::mCurrentSerial = 1;
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +000027const char *fakepath = "C:\\fakepath";
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000028
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000029std::string str(int i)
30{
31 char buffer[20];
32 sprintf(buffer, "%d", i);
33 return buffer;
34}
35
daniel@transgaming.com024f1a92011-09-20 16:06:25 +000036Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize)
37 : type(type), _name(_name), name(Program::undecorate(_name)), arraySize(arraySize)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000038{
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000039 int bytes = UniformTypeSize(type) * arraySize;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000040 data = new unsigned char[bytes];
41 memset(data, 0, bytes);
42 dirty = true;
daniel@transgaming.com2d84df02010-05-14 17:31:13 +000043 handlesSet = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000044}
45
46Uniform::~Uniform()
47{
48 delete[] data;
49}
50
daniel@transgaming.com024f1a92011-09-20 16:06:25 +000051bool Uniform::isArray()
52{
53 return arraySize != 1; // FIXME: Arrays can be of size 1
54}
55
56UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index)
57 : name(Program::undecorate(_name)), element(element), index(index)
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +000058{
59}
60
daniel@transgaming.com73a5db62010-10-15 17:58:13 +000061Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000062{
63 mFragmentShader = NULL;
64 mVertexShader = NULL;
65
66 mPixelExecutable = NULL;
67 mVertexExecutable = NULL;
68 mConstantTablePS = NULL;
69 mConstantTableVS = NULL;
70
daniel@transgaming.comcba50572010-03-28 19:36:09 +000071 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +000072 mValidated = false;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000073
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000074 unlink();
75
76 mDeleteStatus = false;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000077
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000078 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000079}
80
81Program::~Program()
82{
83 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000084
85 if (mVertexShader != NULL)
86 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000087 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000088 }
89
90 if (mFragmentShader != NULL)
91 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000092 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000093 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000094}
95
96bool Program::attachShader(Shader *shader)
97{
98 if (shader->getType() == GL_VERTEX_SHADER)
99 {
100 if (mVertexShader)
101 {
102 return false;
103 }
104
105 mVertexShader = (VertexShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000106 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000107 }
108 else if (shader->getType() == GL_FRAGMENT_SHADER)
109 {
110 if (mFragmentShader)
111 {
112 return false;
113 }
114
115 mFragmentShader = (FragmentShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000116 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000117 }
118 else UNREACHABLE();
119
120 return true;
121}
122
123bool Program::detachShader(Shader *shader)
124{
125 if (shader->getType() == GL_VERTEX_SHADER)
126 {
127 if (mVertexShader != shader)
128 {
129 return false;
130 }
131
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000132 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000133 mVertexShader = NULL;
134 }
135 else if (shader->getType() == GL_FRAGMENT_SHADER)
136 {
137 if (mFragmentShader != shader)
138 {
139 return false;
140 }
141
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000142 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143 mFragmentShader = NULL;
144 }
145 else UNREACHABLE();
146
147 unlink();
148
149 return true;
150}
151
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000152int Program::getAttachedShadersCount() const
153{
154 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
155}
156
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000157IDirect3DPixelShader9 *Program::getPixelShader()
158{
159 return mPixelExecutable;
160}
161
162IDirect3DVertexShader9 *Program::getVertexShader()
163{
164 return mVertexExecutable;
165}
166
167void Program::bindAttributeLocation(GLuint index, const char *name)
168{
169 if (index < MAX_VERTEX_ATTRIBS)
170 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000171 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
172 {
173 mAttributeBinding[i].erase(name);
174 }
175
176 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177 }
178}
179
180GLuint Program::getAttributeLocation(const char *name)
181{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000182 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000183 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000184 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000185 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000186 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000187 {
188 return index;
189 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000190 }
191 }
192
193 return -1;
194}
195
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000196int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000197{
daniel@transgaming.com733ba932011-04-14 15:03:48 +0000198 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
199
200 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000201}
202
daniel@transgaming.com9ba680a2011-05-11 15:37:11 +0000203// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
204// index (0-15 for the pixel shader and 0-3 for the vertex shader).
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000205GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000206{
daniel@transgaming.comdfd57022011-05-11 15:37:25 +0000207 GLuint logicalTextureUnit = -1;
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000208
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000209 switch (type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000211 case SAMPLER_PIXEL:
212 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
213
214 if (mSamplersPS[samplerIndex].active)
215 {
216 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
217 }
218 break;
219 case SAMPLER_VERTEX:
220 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
221
222 if (mSamplersVS[samplerIndex].active)
223 {
224 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
225 }
226 break;
227 default: UNREACHABLE();
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000228 }
229
daniel@transgaming.com3f74c7a2011-05-11 15:36:51 +0000230 if (logicalTextureUnit >= 0 && logicalTextureUnit < getContext()->getMaximumCombinedTextureImageUnits())
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000231 {
232 return logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233 }
234
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000235 return -1;
236}
237
daniel@transgaming.com9ba680a2011-05-11 15:37:11 +0000238// Returns the texture type for a given Direct3D 9 sampler type and
239// index (0-15 for the pixel shader and 0-3 for the vertex shader).
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000240TextureType Program::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000241{
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000242 switch (type)
243 {
244 case SAMPLER_PIXEL:
245 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
246 ASSERT(mSamplersPS[samplerIndex].active);
247 return mSamplersPS[samplerIndex].textureType;
248 case SAMPLER_VERTEX:
249 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
250 ASSERT(mSamplersVS[samplerIndex].active);
251 return mSamplersVS[samplerIndex].textureType;
252 default: UNREACHABLE();
253 }
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000254
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000255 return TEXTURE_2D;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000256}
257
daniel@transgaming.com024f1a92011-09-20 16:06:25 +0000258GLint Program::getUniformLocation(std::string name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000260 int subscript = 0;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000261
daniel@transgaming.comce864422010-11-18 13:16:49 +0000262 // Strip any trailing array operator and retrieve the subscript
daniel@transgaming.com024f1a92011-09-20 16:06:25 +0000263 size_t open = name.find_last_of('[');
264 size_t close = name.find_last_of(']');
265 if (open != std::string::npos && close == name.length() - 1)
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000266 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +0000267 subscript = atoi(name.substr(open + 1).c_str());
268 name.erase(open);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000269 }
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000270
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000271 unsigned int numUniforms = mUniformIndex.size();
272 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000273 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +0000274 if (mUniformIndex[location].name == name &&
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000275 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000276 {
277 return location;
278 }
279 }
280
281 return -1;
282}
283
284bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
285{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000286 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000287 {
288 return false;
289 }
290
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000291 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000292 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000293
294 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000295 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000296 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000297
298 if (arraySize == 1 && count > 1)
299 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
300
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000301 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000302
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000303 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
304 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000305 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000306 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000307 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000308 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000309
310 if (arraySize == 1 && count > 1)
311 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000312
313 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000314 GLboolean *boolParams = new GLboolean[count];
315
316 for (int i = 0; i < count; ++i)
317 {
318 if (v[i] == 0.0f)
319 {
320 boolParams[i] = GL_FALSE;
321 }
322 else
323 {
324 boolParams[i] = GL_TRUE;
325 }
326 }
327
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000328 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
329 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000330
331 delete [] boolParams;
332 }
333 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000334 {
335 return false;
336 }
337
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000338 return true;
339}
340
341bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
342{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000343 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000344 {
345 return false;
346 }
347
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000348 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000349 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000350
351 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000352 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000353 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000354
355 if (arraySize == 1 && count > 1)
356 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
357
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000358 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000359
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000360 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
361 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000362 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000363 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000364 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000365 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000366
367 if (arraySize == 1 && count > 1)
368 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
369
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000370 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
371
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000372 GLboolean *boolParams = new GLboolean[count * 2];
373
374 for (int i = 0; i < count * 2; ++i)
375 {
376 if (v[i] == 0.0f)
377 {
378 boolParams[i] = GL_FALSE;
379 }
380 else
381 {
382 boolParams[i] = GL_TRUE;
383 }
384 }
385
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000386 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
387 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000388
389 delete [] boolParams;
390 }
391 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000392 {
393 return false;
394 }
395
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000396 return true;
397}
398
399bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
400{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000401 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000402 {
403 return false;
404 }
405
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000406 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000407 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000408
409 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000410 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000411 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000412
413 if (arraySize == 1 && count > 1)
414 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
415
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000416 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000417
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000418 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
419 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000420 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000421 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000422 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000423 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000424
425 if (arraySize == 1 && count > 1)
426 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
427
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000428 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000429 GLboolean *boolParams = new GLboolean[count * 3];
430
431 for (int i = 0; i < count * 3; ++i)
432 {
433 if (v[i] == 0.0f)
434 {
435 boolParams[i] = GL_FALSE;
436 }
437 else
438 {
439 boolParams[i] = GL_TRUE;
440 }
441 }
442
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000443 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
444 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000445
446 delete [] boolParams;
447 }
448 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000449 {
450 return false;
451 }
452
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000453 return true;
454}
455
456bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
457{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000458 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000459 {
460 return false;
461 }
462
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000463 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000464 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000465
466 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000467 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000468 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000469
470 if (arraySize == 1 && count > 1)
471 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
472
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000473 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000474
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000475 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
476 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000477 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000478 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000479 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000480 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000481
482 if (arraySize == 1 && count > 1)
483 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
484
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000485 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000486 GLboolean *boolParams = new GLboolean[count * 4];
487
488 for (int i = 0; i < count * 4; ++i)
489 {
490 if (v[i] == 0.0f)
491 {
492 boolParams[i] = GL_FALSE;
493 }
494 else
495 {
496 boolParams[i] = GL_TRUE;
497 }
498 }
499
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000500 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
501 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000502
503 delete [] boolParams;
504 }
505 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000506 {
507 return false;
508 }
509
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000510 return true;
511}
512
513bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
514{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000515 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000516 {
517 return false;
518 }
519
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000520 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000521 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000522
523 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000524 {
525 return false;
526 }
527
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000528 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000529
530 if (arraySize == 1 && count > 1)
531 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
532
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000533 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000534
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000535 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
536 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000537
538 return true;
539}
540
541bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
542{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000543 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000544 {
545 return false;
546 }
547
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000548 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000549 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000550
551 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000552 {
553 return false;
554 }
555
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000556 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000557
558 if (arraySize == 1 && count > 1)
559 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
560
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000561 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000562
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000563 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
564 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000565
566 return true;
567}
568
569bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
570{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000571 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000572 {
573 return false;
574 }
575
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000576 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000577 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000578
579 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000580 {
581 return false;
582 }
583
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000584 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000585
586 if (arraySize == 1 && count > 1)
587 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
588
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000589 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000590
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000591 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
592 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000593
594 return true;
595}
596
597bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
598{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000599 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000600 {
601 return false;
602 }
603
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000604 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000605 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000606
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000607 if (targetUniform->type == GL_INT ||
608 targetUniform->type == GL_SAMPLER_2D ||
609 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000610 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000611 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000612
613 if (arraySize == 1 && count > 1)
614 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
615
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000616 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000617
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000618 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
619 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000620 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000621 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000622 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000623 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000624
625 if (arraySize == 1 && count > 1)
626 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
627
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000628 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000629 GLboolean *boolParams = new GLboolean[count];
630
631 for (int i = 0; i < count; ++i)
632 {
633 if (v[i] == 0)
634 {
635 boolParams[i] = GL_FALSE;
636 }
637 else
638 {
639 boolParams[i] = GL_TRUE;
640 }
641 }
642
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000643 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
644 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000645
646 delete [] boolParams;
647 }
648 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000649 {
650 return false;
651 }
652
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000653 return true;
654}
655
656bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
657{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000658 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000659 {
660 return false;
661 }
662
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000663 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000664 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000665
666 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000667 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000668 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000669
670 if (arraySize == 1 && count > 1)
671 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
672
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000673 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000674
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000675 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
676 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000677 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000678 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000679 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000680 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000681
682 if (arraySize == 1 && count > 1)
683 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
684
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000685 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000686 GLboolean *boolParams = new GLboolean[count * 2];
687
688 for (int i = 0; i < count * 2; ++i)
689 {
690 if (v[i] == 0)
691 {
692 boolParams[i] = GL_FALSE;
693 }
694 else
695 {
696 boolParams[i] = GL_TRUE;
697 }
698 }
699
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000700 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
701 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000702
703 delete [] boolParams;
704 }
705 else
706 {
707 return false;
708 }
709
710 return true;
711}
712
713bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
714{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000715 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000716 {
717 return false;
718 }
719
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000720 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000721 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000722
723 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000724 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000725 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000726
727 if (arraySize == 1 && count > 1)
728 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
729
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000730 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000731
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000732 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
733 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000734 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000735 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000736 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000737 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000738
739 if (arraySize == 1 && count > 1)
740 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
741
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000742 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000743 GLboolean *boolParams = new GLboolean[count * 3];
744
745 for (int i = 0; i < count * 3; ++i)
746 {
747 if (v[i] == 0)
748 {
749 boolParams[i] = GL_FALSE;
750 }
751 else
752 {
753 boolParams[i] = GL_TRUE;
754 }
755 }
756
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000757 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
758 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000759
760 delete [] boolParams;
761 }
762 else
763 {
764 return false;
765 }
766
767 return true;
768}
769
770bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
771{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000772 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000773 {
774 return false;
775 }
776
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000777 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000778 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000779
780 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000781 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000782 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000783
784 if (arraySize == 1 && count > 1)
785 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
786
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000787 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000788
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000789 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
790 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000791 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000792 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000793 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000794 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000795
796 if (arraySize == 1 && count > 1)
797 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
798
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000799 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000800 GLboolean *boolParams = new GLboolean[count * 4];
801
802 for (int i = 0; i < count * 4; ++i)
803 {
804 if (v[i] == 0)
805 {
806 boolParams[i] = GL_FALSE;
807 }
808 else
809 {
810 boolParams[i] = GL_TRUE;
811 }
812 }
813
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000814 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
815 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000816
817 delete [] boolParams;
818 }
819 else
820 {
821 return false;
822 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000823
824 return true;
825}
826
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000827bool Program::getUniformfv(GLint location, GLfloat *params)
828{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000829 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000830 {
831 return false;
832 }
833
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000834 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000835
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000836 unsigned int count = UniformComponentCount(targetUniform->type);
837
838 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000839 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000840 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000841 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000842 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000843
844 for (unsigned int i = 0; i < count; ++i)
845 {
846 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
847 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000848 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000849 break;
850 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000851 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
852 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000853 break;
854 case GL_INT:
855 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000856 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000857
858 for (unsigned int i = 0; i < count; ++i)
859 {
860 params[i] = (float)intParams[i];
861 }
862 }
863 break;
864 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000865 }
866
867 return true;
868}
869
870bool Program::getUniformiv(GLint location, GLint *params)
871{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000872 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000873 {
874 return false;
875 }
876
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000877 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000878
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000879 unsigned int count = UniformComponentCount(targetUniform->type);
880
881 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000882 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000883 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000884 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000885 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000886
887 for (unsigned int i = 0; i < count; ++i)
888 {
889 params[i] = (GLint)boolParams[i];
890 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000891 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000892 break;
893 case GL_FLOAT:
894 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000895 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000896
897 for (unsigned int i = 0; i < count; ++i)
898 {
899 params[i] = (GLint)floatParams[i];
900 }
901 }
902 break;
903 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000904 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
905 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000906 break;
907 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000908 }
909
910 return true;
911}
912
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000913void Program::dirtyAllUniforms()
914{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000915 unsigned int numUniforms = mUniforms.size();
916 for (unsigned int index = 0; index < numUniforms; index++)
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000917 {
918 mUniforms[index]->dirty = true;
919 }
920}
921
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000922// Applies all the uniforms set for this program object to the Direct3D 9 device
923void Program::applyUniforms()
924{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000925 unsigned int numUniforms = mUniformIndex.size();
926 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000927 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000928 if (mUniformIndex[location].element != 0)
929 {
930 continue;
931 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000932
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000933 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
934
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000935 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000936 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000937 int arraySize = targetUniform->arraySize;
938 GLfloat *f = (GLfloat*)targetUniform->data;
939 GLint *i = (GLint*)targetUniform->data;
940 GLboolean *b = (GLboolean*)targetUniform->data;
941
942 switch (targetUniform->type)
943 {
944 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
945 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
946 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
947 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
948 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
949 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
950 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
951 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
952 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
953 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
954 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000955 case GL_SAMPLER_2D:
956 case GL_SAMPLER_CUBE:
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000957 case GL_INT: applyUniform1iv(location, arraySize, i); break;
958 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
959 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
960 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
961 default:
962 UNREACHABLE();
963 }
964
965 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000966 }
967 }
968}
969
970// Compiles the HLSL code of the attached shaders into executable binaries
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000971ID3D10Blob *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000972{
973 if (!hlsl)
974 {
975 return NULL;
976 }
977
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000978 DWORD result;
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000979 UINT flags = 0;
980 std::string sourceText;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000981 if (perfActive())
982 {
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000983 flags |= D3DCOMPILE_DEBUG;
984#ifdef NDEBUG
985 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
986#else
987 flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000988#endif
989
990 std::string sourcePath = getTempPath();
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000991 sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000992 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000993 }
994 else
995 {
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +0000996 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
997 sourceText = hlsl;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000998 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000999
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001000 ID3D10Blob *binary = NULL;
1001 ID3D10Blob *errorMessage = NULL;
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00001002 result = D3DCompile(hlsl, strlen(hlsl), fakepath, NULL, NULL, "main", profile, flags, 0, &binary, &errorMessage);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001003
1004 if (errorMessage)
1005 {
1006 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001007
daniel@transgaming.com87891f72011-06-01 15:28:35 +00001008 appendToInfoLogSanitized(message);
daniel@transgaming.com0599dc62010-03-21 04:31:36 +00001009 TRACE("\n%s", hlsl);
1010 TRACE("\n%s", message);
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001011
1012 errorMessage->Release();
1013 errorMessage = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001014 }
1015
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001016 if (FAILED(result))
1017 {
1018 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1019 {
1020 error(GL_OUT_OF_MEMORY);
1021 }
1022
1023 return NULL;
1024 }
1025
1026 result = D3DXGetShaderConstantTable(static_cast<const DWORD*>(binary->GetBufferPointer()), constantTable);
1027
1028 if (FAILED(result))
1029 {
1030 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1031 {
1032 error(GL_OUT_OF_MEMORY);
1033 }
1034
1035 binary->Release();
1036
1037 return NULL;
1038 }
1039
1040 return binary;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001041}
1042
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001043// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1044// Returns the number of used varying registers, or -1 if unsuccesful
1045int Program::packVaryings(const Varying *packing[][4])
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001046{
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001047 Context *context = getContext();
1048 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1049
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001050 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001051 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001052 int n = VariableRowCount(varying->type) * varying->size;
1053 int m = VariableColumnCount(varying->type);
1054 bool success = false;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001055
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001056 if (m == 2 || m == 3 || m == 4)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001057 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001058 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001059 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001060 bool available = true;
1061
1062 for (int y = 0; y < n && available; y++)
1063 {
1064 for (int x = 0; x < m && available; x++)
1065 {
1066 if (packing[r + y][x])
1067 {
1068 available = false;
1069 }
1070 }
1071 }
1072
1073 if (available)
1074 {
1075 varying->reg = r;
1076 varying->col = 0;
1077
1078 for (int y = 0; y < n; y++)
1079 {
1080 for (int x = 0; x < m; x++)
1081 {
1082 packing[r + y][x] = &*varying;
1083 }
1084 }
1085
1086 success = true;
1087 }
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001088 }
1089
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001090 if (!success && m == 2)
1091 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001092 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001093 {
1094 bool available = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001095
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001096 for (int y = 0; y < n && available; y++)
1097 {
1098 for (int x = 2; x < 4 && available; x++)
1099 {
1100 if (packing[r + y][x])
1101 {
1102 available = false;
1103 }
1104 }
1105 }
1106
1107 if (available)
1108 {
1109 varying->reg = r;
1110 varying->col = 2;
1111
1112 for (int y = 0; y < n; y++)
1113 {
1114 for (int x = 2; x < 4; x++)
1115 {
1116 packing[r + y][x] = &*varying;
1117 }
1118 }
1119
1120 success = true;
1121 }
1122 }
1123 }
1124 }
1125 else if (m == 1)
1126 {
1127 int space[4] = {0};
1128
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001129 for (int y = 0; y < maxVaryingVectors; y++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001130 {
1131 for (int x = 0; x < 4; x++)
1132 {
1133 space[x] += packing[y][x] ? 0 : 1;
1134 }
1135 }
1136
1137 int column = 0;
1138
1139 for (int x = 0; x < 4; x++)
1140 {
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001141 if (space[x] >= n && space[x] < space[column])
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001142 {
1143 column = x;
1144 }
1145 }
1146
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001147 if (space[column] >= n)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001148 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001149 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001150 {
1151 if (!packing[r][column])
1152 {
1153 varying->reg = r;
1154
1155 for (int y = r; y < r + n; y++)
1156 {
1157 packing[y][column] = &*varying;
1158 }
1159
1160 break;
1161 }
1162 }
1163
1164 varying->col = column;
1165
1166 success = true;
1167 }
1168 }
1169 else UNREACHABLE();
1170
1171 if (!success)
1172 {
1173 appendToInfoLog("Could not pack varying %s", varying->name.c_str());
1174
1175 return -1;
1176 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001177 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001178
1179 // Return the number of used registers
1180 int registers = 0;
1181
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001182 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001183 {
1184 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1185 {
1186 registers++;
1187 }
1188 }
1189
1190 return registers;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001191}
1192
1193bool Program::linkVaryings()
1194{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001195 if (mPixelHLSL.empty() || mVertexHLSL.empty())
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001196 {
1197 return false;
1198 }
1199
daniel@transgaming.com97750022011-02-11 13:23:13 +00001200 // Reset the varying register assignments
1201 for (VaryingList::iterator fragVar = mFragmentShader->varyings.begin(); fragVar != mFragmentShader->varyings.end(); fragVar++)
1202 {
1203 fragVar->reg = -1;
1204 fragVar->col = -1;
1205 }
1206
1207 for (VaryingList::iterator vtxVar = mVertexShader->varyings.begin(); vtxVar != mVertexShader->varyings.end(); vtxVar++)
1208 {
1209 vtxVar->reg = -1;
1210 vtxVar->col = -1;
1211 }
1212
1213 // Map the varyings to the register file
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001214 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001215 int registers = packVaryings(packing);
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001216
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001217 if (registers < 0)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001218 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001219 return false;
1220 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001221
daniel@transgaming.com97750022011-02-11 13:23:13 +00001222 // Write the HLSL input/output declarations
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001223 Context *context = getContext();
1224 const bool sm3 = context->supportsShaderModel3();
1225 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1226
1227 if (registers == maxVaryingVectors && mFragmentShader->mUsesFragCoord)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001228 {
1229 appendToInfoLog("No varying registers left to support gl_FragCoord");
1230
1231 return false;
1232 }
1233
1234 for (VaryingList::iterator input = mFragmentShader->varyings.begin(); input != mFragmentShader->varyings.end(); input++)
1235 {
1236 bool matched = false;
1237
1238 for (VaryingList::iterator output = mVertexShader->varyings.begin(); output != mVertexShader->varyings.end(); output++)
1239 {
1240 if (output->name == input->name)
1241 {
1242 if (output->type != input->type || output->size != input->size)
1243 {
1244 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
1245
1246 return false;
1247 }
1248
1249 output->reg = input->reg;
1250 output->col = input->col;
1251
1252 matched = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001253 break;
1254 }
1255 }
1256
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001257 if (!matched)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001258 {
daniel@transgaming.com97750022011-02-11 13:23:13 +00001259 appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001260
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001261 return false;
1262 }
1263 }
1264
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001265 std::string varyingSemantic = (sm3 ? "COLOR" : "TEXCOORD");
1266
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001267 mVertexHLSL += "struct VS_INPUT\n"
1268 "{\n";
1269
1270 int semanticIndex = 0;
1271 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1272 {
1273 switch (attribute->type)
1274 {
1275 case GL_FLOAT: mVertexHLSL += " float "; break;
1276 case GL_FLOAT_VEC2: mVertexHLSL += " float2 "; break;
1277 case GL_FLOAT_VEC3: mVertexHLSL += " float3 "; break;
1278 case GL_FLOAT_VEC4: mVertexHLSL += " float4 "; break;
1279 case GL_FLOAT_MAT2: mVertexHLSL += " float2x2 "; break;
1280 case GL_FLOAT_MAT3: mVertexHLSL += " float3x3 "; break;
1281 case GL_FLOAT_MAT4: mVertexHLSL += " float4x4 "; break;
1282 default: UNREACHABLE();
1283 }
1284
1285 mVertexHLSL += decorate(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1286
1287 semanticIndex += VariableRowCount(attribute->type);
1288 }
1289
1290 mVertexHLSL += "};\n"
1291 "\n"
1292 "struct VS_OUTPUT\n"
1293 "{\n"
1294 " float4 gl_Position : POSITION;\n";
1295
1296 for (int r = 0; r < registers; r++)
1297 {
1298 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1299
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001300 mVertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001301 }
1302
1303 if (mFragmentShader->mUsesFragCoord)
1304 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001305 mVertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1306 }
1307
1308 if (mVertexShader->mUsesPointSize && sm3)
1309 {
1310 mVertexHLSL += " float gl_PointSize : PSIZE;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001311 }
1312
1313 mVertexHLSL += "};\n"
1314 "\n"
1315 "VS_OUTPUT main(VS_INPUT input)\n"
1316 "{\n";
1317
1318 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1319 {
1320 mVertexHLSL += " " + decorate(attribute->name) + " = ";
1321
1322 if (VariableRowCount(attribute->type) > 1) // Matrix
1323 {
1324 mVertexHLSL += "transpose";
1325 }
1326
1327 mVertexHLSL += "(input." + decorate(attribute->name) + ");\n";
1328 }
1329
1330 mVertexHLSL += "\n"
1331 " gl_main();\n"
1332 "\n"
1333 " VS_OUTPUT output;\n"
1334 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001335 " output.gl_Position.y = gl_Position.y - dx_HalfPixelSize.y * gl_Position.w;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001336 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1337 " output.gl_Position.w = gl_Position.w;\n";
1338
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001339 if (mVertexShader->mUsesPointSize && sm3)
1340 {
1341 mVertexHLSL += " output.gl_PointSize = clamp(gl_PointSize, 1.0, " + str((int)ALIASED_POINT_SIZE_RANGE_MAX_SM3) + ");\n";
1342 }
1343
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001344 if (mFragmentShader->mUsesFragCoord)
1345 {
1346 mVertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1347 }
1348
1349 for (VaryingList::iterator varying = mVertexShader->varyings.begin(); varying != mVertexShader->varyings.end(); varying++)
1350 {
1351 if (varying->reg >= 0)
1352 {
1353 for (int i = 0; i < varying->size; i++)
1354 {
1355 int rows = VariableRowCount(varying->type);
1356
1357 for (int j = 0; j < rows; j++)
1358 {
1359 int r = varying->reg + i * rows + j;
1360 mVertexHLSL += " output.v" + str(r);
1361
1362 bool sharedRegister = false; // Register used by multiple varyings
1363
1364 for (int x = 0; x < 4; x++)
1365 {
1366 if (packing[r][x] && packing[r][x] != packing[r][0])
1367 {
1368 sharedRegister = true;
1369 break;
1370 }
1371 }
1372
1373 if(sharedRegister)
1374 {
1375 mVertexHLSL += ".";
1376
1377 for (int x = 0; x < 4; x++)
1378 {
1379 if (packing[r][x] == &*varying)
1380 {
1381 switch(x)
1382 {
1383 case 0: mVertexHLSL += "x"; break;
1384 case 1: mVertexHLSL += "y"; break;
1385 case 2: mVertexHLSL += "z"; break;
1386 case 3: mVertexHLSL += "w"; break;
1387 }
1388 }
1389 }
1390 }
1391
1392 mVertexHLSL += " = " + varying->name;
1393
1394 if (varying->array)
1395 {
1396 mVertexHLSL += "[" + str(i) + "]";
1397 }
1398
1399 if (rows > 1)
1400 {
1401 mVertexHLSL += "[" + str(j) + "]";
1402 }
1403
1404 mVertexHLSL += ";\n";
1405 }
1406 }
1407 }
1408 }
1409
1410 mVertexHLSL += "\n"
1411 " return output;\n"
1412 "}\n";
1413
1414 mPixelHLSL += "struct PS_INPUT\n"
1415 "{\n";
1416
1417 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1418 {
1419 if (varying->reg >= 0)
1420 {
1421 for (int i = 0; i < varying->size; i++)
1422 {
1423 int rows = VariableRowCount(varying->type);
1424 for (int j = 0; j < rows; j++)
1425 {
1426 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001427 mPixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001428 }
1429 }
1430 }
1431 else UNREACHABLE();
1432 }
1433
1434 if (mFragmentShader->mUsesFragCoord)
1435 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001436 mPixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001437 if (sm3) {
daniel@transgaming.com996675c2010-11-17 13:06:29 +00001438 mPixelHLSL += " float2 dx_VPos : VPOS;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001439 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001440 }
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001441
1442 if (mFragmentShader->mUsesPointCoord && sm3)
1443 {
1444 mPixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1445 }
1446
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001447 if (mFragmentShader->mUsesFrontFacing)
1448 {
1449 mPixelHLSL += " float vFace : VFACE;\n";
1450 }
1451
1452 mPixelHLSL += "};\n"
1453 "\n"
1454 "struct PS_OUTPUT\n"
1455 "{\n"
1456 " float4 gl_Color[1] : COLOR;\n"
1457 "};\n"
1458 "\n"
1459 "PS_OUTPUT main(PS_INPUT input)\n"
1460 "{\n";
1461
1462 if (mFragmentShader->mUsesFragCoord)
1463 {
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001464 mPixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1465 if (sm3) {
apatrick@chromium.orgb1092bf2011-05-11 19:52:39 +00001466 mPixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
1467 " gl_FragCoord.y = 2.0 * dx_Viewport.y - input.dx_VPos.y - 0.5;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001468 } else {
1469 mPixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Viewport.x + dx_Viewport.z;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001470 " gl_FragCoord.y = -(input.gl_FragCoord.y * rhw) * dx_Viewport.y + dx_Viewport.w;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001471 }
1472 mPixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001473 " gl_FragCoord.w = rhw;\n";
1474 }
1475
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001476 if (mFragmentShader->mUsesPointCoord && sm3)
1477 {
apatrick@chromium.orgda4d0492011-01-22 00:16:10 +00001478 mPixelHLSL += " gl_PointCoord = input.gl_PointCoord;\n";
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001479 }
1480
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001481 if (mFragmentShader->mUsesFrontFacing)
1482 {
1483 mPixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1484 }
1485
1486 for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
1487 {
1488 if (varying->reg >= 0)
1489 {
1490 for (int i = 0; i < varying->size; i++)
1491 {
1492 int rows = VariableRowCount(varying->type);
1493 for (int j = 0; j < rows; j++)
1494 {
1495 std::string n = str(varying->reg + i * rows + j);
1496 mPixelHLSL += " " + varying->name;
1497
1498 if (varying->array)
1499 {
1500 mPixelHLSL += "[" + str(i) + "]";
1501 }
1502
1503 if (rows > 1)
1504 {
1505 mPixelHLSL += "[" + str(j) + "]";
1506 }
1507
1508 mPixelHLSL += " = input.v" + n + ";\n";
1509 }
1510 }
1511 }
1512 else UNREACHABLE();
1513 }
1514
1515 mPixelHLSL += "\n"
1516 " gl_main();\n"
1517 "\n"
1518 " PS_OUTPUT output;\n"
1519 " output.gl_Color[0] = gl_Color[0];\n"
1520 "\n"
1521 " return output;\n"
1522 "}\n";
1523
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001524 return true;
1525}
1526
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001527// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1528// compiling them into binaries, determining the attribute mappings, and collecting
1529// a list of uniforms
1530void Program::link()
1531{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001532 unlink();
1533
1534 if (!mFragmentShader || !mFragmentShader->isCompiled())
1535 {
1536 return;
1537 }
1538
1539 if (!mVertexShader || !mVertexShader->isCompiled())
1540 {
1541 return;
1542 }
1543
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001544 mPixelHLSL = mFragmentShader->getHLSL();
1545 mVertexHLSL = mVertexShader->getHLSL();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001546
1547 if (!linkVaryings())
1548 {
1549 return;
1550 }
1551
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001552 Context *context = getContext();
1553 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1554 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1555
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001556 ID3D10Blob *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1557 ID3D10Blob *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001558
1559 if (vertexBinary && pixelBinary)
1560 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001561 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001562 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1563 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1564
1565 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1566 {
1567 return error(GL_OUT_OF_MEMORY);
1568 }
1569
1570 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001571
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001572 vertexBinary->Release();
1573 pixelBinary->Release();
1574 vertexBinary = NULL;
1575 pixelBinary = NULL;
1576
1577 if (mVertexExecutable && mPixelExecutable)
1578 {
1579 if (!linkAttributes())
1580 {
1581 return;
1582 }
1583
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001584 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001585 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001586 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001587 }
1588
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001589 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001590 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001591 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001592 }
1593
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001594 // these uniforms are searched as already-decorated because gl_ and dx_
1595 // are reserved prefixes, and do not receive additional decoration
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001596 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
1597 mDxDepthLocation = getUniformLocation("dx_Depth");
1598 mDxViewportLocation = getUniformLocation("dx_Viewport");
1599 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
1600 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
1601 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00001602
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001603 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001604 }
1605 }
1606}
1607
1608// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1609bool Program::linkAttributes()
1610{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001611 unsigned int usedLocations = 0;
1612
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001613 // Link attributes that have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001614 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001615 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001616 int location = getAttributeBinding(attribute->name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001617
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001618 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001619 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001620 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001621 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001622 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001623 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001624
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001625 mLinkedAttribute[location] = *attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001626
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001627 int rows = VariableRowCount(attribute->type);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001628
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001629 if (rows + location > MAX_VERTEX_ATTRIBS)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001630 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001631 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 +00001632
1633 return false;
1634 }
1635
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001636 for (int i = 0; i < rows; i++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001637 {
1638 usedLocations |= 1 << (location + i);
1639 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001640 }
1641 }
1642
1643 // Link attributes that don't have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001644 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001645 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001646 int location = getAttributeBinding(attribute->name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001647
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001648 if (location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001649 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001650 int rows = VariableRowCount(attribute->type);
1651 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001652
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001653 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001654 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001655 appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001656
1657 return false; // Fail to link
1658 }
1659
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001660 mLinkedAttribute[availableIndex] = *attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001661 }
1662 }
1663
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001664 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001665 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001666 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001667 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001668
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001669 for (int r = 0; r < rows; r++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001670 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001671 mSemanticIndex[attributeIndex++] = index++;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001672 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001673 }
1674
1675 return true;
1676}
1677
daniel@transgaming.com85423182010-04-22 13:35:27 +00001678int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001679{
1680 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1681 {
1682 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1683 {
1684 return location;
1685 }
1686 }
1687
1688 return -1;
1689}
1690
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001691bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1692{
1693 D3DXCONSTANTTABLE_DESC constantTableDescription;
1694 D3DXCONSTANT_DESC constantDescription;
1695 UINT descriptionCount = 1;
1696
1697 constantTable->GetDesc(&constantTableDescription);
1698
1699 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1700 {
1701 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001702 HRESULT result = constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1703 ASSERT(SUCCEEDED(result));
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001704
1705 if (!defineUniform(constantHandle, constantDescription))
1706 {
1707 return false;
1708 }
1709 }
1710
1711 return true;
1712}
1713
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001714// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001715// Returns true if succesful (uniform not already defined)
1716bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1717{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001718 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1719 {
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001720 for (unsigned int samplerIndex = constantDescription.RegisterIndex; samplerIndex < constantDescription.RegisterIndex + constantDescription.RegisterCount; samplerIndex++)
1721 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001722 if (mConstantTablePS->GetConstantByName(NULL, constantDescription.Name) != NULL)
1723 {
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001724 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1725 {
1726 mSamplersPS[samplerIndex].active = true;
1727 mSamplersPS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1728 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
1729 }
1730 else
1731 {
1732 appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
1733 return false;
1734 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001735 }
1736
1737 if (mConstantTableVS->GetConstantByName(NULL, constantDescription.Name) != NULL)
1738 {
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001739 if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
1740 {
1741 mSamplersVS[samplerIndex].active = true;
1742 mSamplersVS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1743 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
1744 }
1745 else
1746 {
1747 appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
1748 return false;
1749 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001750 }
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001751 }
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001752 }
1753
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001754 switch(constantDescription.Class)
1755 {
1756 case D3DXPC_STRUCT:
1757 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001758 for (unsigned int arrayIndex = 0; arrayIndex < constantDescription.Elements; arrayIndex++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001759 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001760 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001761 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001762 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1763
1764 D3DXCONSTANT_DESC fieldDescription;
1765 UINT descriptionCount = 1;
1766
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001767 HRESULT result = mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1768 ASSERT(SUCCEEDED(result));
daniel@transgaming.comce864422010-11-18 13:16:49 +00001769
1770 std::string structIndex = (constantDescription.Elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
1771
1772 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + structIndex + "."))
1773 {
1774 return false;
1775 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001776 }
1777 }
1778
1779 return true;
1780 }
1781 case D3DXPC_SCALAR:
1782 case D3DXPC_VECTOR:
1783 case D3DXPC_MATRIX_COLUMNS:
1784 case D3DXPC_OBJECT:
1785 return defineUniform(constantDescription, name + constantDescription.Name);
1786 default:
1787 UNREACHABLE();
1788 return false;
1789 }
1790}
1791
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001792bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &_name)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001793{
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001794 Uniform *uniform = createUniform(constantDescription, _name);
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001795
1796 if(!uniform)
1797 {
1798 return false;
1799 }
1800
1801 // Check if already defined
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001802 GLint location = getUniformLocation(uniform->name);
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001803 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001804
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001805 if (location >= 0)
1806 {
1807 delete uniform;
1808
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001809 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001810 {
1811 return false;
1812 }
1813 else
1814 {
1815 return true;
1816 }
1817 }
1818
1819 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001820 unsigned int uniformIndex = mUniforms.size() - 1;
1821
1822 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1823 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001824 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001825 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001826
1827 return true;
1828}
1829
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001830Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &_name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001831{
1832 if (constantDescription.Rows == 1) // Vectors and scalars
1833 {
1834 switch (constantDescription.Type)
1835 {
1836 case D3DXPT_SAMPLER2D:
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001837 switch (constantDescription.Columns)
1838 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001839 case 1: return new Uniform(GL_SAMPLER_2D, _name, constantDescription.Elements);
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001840 default: UNREACHABLE();
1841 }
1842 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001843 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001844 switch (constantDescription.Columns)
1845 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001846 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001847 default: UNREACHABLE();
1848 }
1849 break;
1850 case D3DXPT_BOOL:
1851 switch (constantDescription.Columns)
1852 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001853 case 1: return new Uniform(GL_BOOL, _name, constantDescription.Elements);
1854 case 2: return new Uniform(GL_BOOL_VEC2, _name, constantDescription.Elements);
1855 case 3: return new Uniform(GL_BOOL_VEC3, _name, constantDescription.Elements);
1856 case 4: return new Uniform(GL_BOOL_VEC4, _name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001857 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001858 }
1859 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001860 case D3DXPT_INT:
1861 switch (constantDescription.Columns)
1862 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001863 case 1: return new Uniform(GL_INT, _name, constantDescription.Elements);
1864 case 2: return new Uniform(GL_INT_VEC2, _name, constantDescription.Elements);
1865 case 3: return new Uniform(GL_INT_VEC3, _name, constantDescription.Elements);
1866 case 4: return new Uniform(GL_INT_VEC4, _name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001867 default: UNREACHABLE();
1868 }
1869 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001870 case D3DXPT_FLOAT:
1871 switch (constantDescription.Columns)
1872 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001873 case 1: return new Uniform(GL_FLOAT, _name, constantDescription.Elements);
1874 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constantDescription.Elements);
1875 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constantDescription.Elements);
1876 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001877 default: UNREACHABLE();
1878 }
1879 break;
1880 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001881 UNREACHABLE();
1882 }
1883 }
1884 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1885 {
1886 switch (constantDescription.Type)
1887 {
1888 case D3DXPT_FLOAT:
1889 switch (constantDescription.Rows)
1890 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001891 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constantDescription.Elements);
1892 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constantDescription.Elements);
1893 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001894 default: UNREACHABLE();
1895 }
1896 break;
1897 default: UNREACHABLE();
1898 }
1899 }
1900 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001901
1902 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001903}
1904
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001905// This method needs to match OutputHLSL::decorate
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001906std::string Program::decorate(const std::string &name)
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001907{
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001908 if (name.substr(0, 3) != "gl_" && name.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001909 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001910 return "_" + name;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001911 }
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001912
1913 return name;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001914}
1915
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001916std::string Program::undecorate(const std::string &_name)
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001917{
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001918 if (_name.substr(0, 1) == "_")
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001919 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001920 return _name.substr(1);
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001921 }
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001922
1923 return _name;
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001924}
1925
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001926bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1927{
1928 BOOL *vector = new BOOL[count];
1929 for (int i = 0; i < count; i++)
1930 {
1931 if (v[i] == GL_FALSE)
1932 vector[i] = 0;
1933 else
1934 vector[i] = 1;
1935 }
1936
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001937 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1938
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001939 D3DXHANDLE constantPS;
1940 D3DXHANDLE constantVS;
1941 getConstantHandles(targetUniform, &constantPS, &constantVS);
1942
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001943 IDirect3DDevice9 *device = getDevice();
1944
1945 if (constantPS)
1946 {
1947 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1948 }
1949
1950 if (constantVS)
1951 {
1952 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1953 }
1954
1955 delete [] vector;
1956
1957 return true;
1958}
1959
1960bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1961{
1962 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1963
1964 for (int i = 0; i < count; i++)
1965 {
1966 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1967 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1968
1969 v += 2;
1970 }
1971
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001972 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1973
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001974 D3DXHANDLE constantPS;
1975 D3DXHANDLE constantVS;
1976 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001977 IDirect3DDevice9 *device = getDevice();
1978
1979 if (constantPS)
1980 {
1981 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1982 }
1983
1984 if (constantVS)
1985 {
1986 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1987 }
1988
1989 delete[] vector;
1990
1991 return true;
1992}
1993
1994bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1995{
1996 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1997
1998 for (int i = 0; i < count; i++)
1999 {
2000 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
2001 (v[1] == GL_FALSE ? 0.0f : 1.0f),
2002 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
2003
2004 v += 3;
2005 }
2006
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002007 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2008
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002009 D3DXHANDLE constantPS;
2010 D3DXHANDLE constantVS;
2011 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002012 IDirect3DDevice9 *device = getDevice();
2013
2014 if (constantPS)
2015 {
2016 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2017 }
2018
2019 if (constantVS)
2020 {
2021 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2022 }
2023
2024 delete[] vector;
2025
2026 return true;
2027}
2028
2029bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
2030{
2031 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2032
2033 for (int i = 0; i < count; i++)
2034 {
2035 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
2036 (v[1] == GL_FALSE ? 0.0f : 1.0f),
2037 (v[2] == GL_FALSE ? 0.0f : 1.0f),
2038 (v[3] == GL_FALSE ? 0.0f : 1.0f));
2039
2040 v += 3;
2041 }
2042
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002043 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2044
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002045 D3DXHANDLE constantPS;
2046 D3DXHANDLE constantVS;
2047 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002048 IDirect3DDevice9 *device = getDevice();
2049
2050 if (constantPS)
2051 {
2052 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2053 }
2054
2055 if (constantVS)
2056 {
2057 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2058 }
2059
2060 delete [] vector;
2061
2062 return true;
2063}
2064
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002065bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
2066{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002067 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2068
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002069 D3DXHANDLE constantPS;
2070 D3DXHANDLE constantVS;
2071 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002072 IDirect3DDevice9 *device = getDevice();
2073
2074 if (constantPS)
2075 {
2076 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
2077 }
2078
2079 if (constantVS)
2080 {
2081 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
2082 }
2083
2084 return true;
2085}
2086
2087bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
2088{
2089 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2090
2091 for (int i = 0; i < count; i++)
2092 {
2093 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
2094
2095 v += 2;
2096 }
2097
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002098 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2099
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002100 D3DXHANDLE constantPS;
2101 D3DXHANDLE constantVS;
2102 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002103 IDirect3DDevice9 *device = getDevice();
2104
2105 if (constantPS)
2106 {
2107 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2108 }
2109
2110 if (constantVS)
2111 {
2112 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2113 }
2114
2115 delete[] vector;
2116
2117 return true;
2118}
2119
2120bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
2121{
2122 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2123
2124 for (int i = 0; i < count; i++)
2125 {
2126 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
2127
2128 v += 3;
2129 }
2130
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002131 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2132
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002133 D3DXHANDLE constantPS;
2134 D3DXHANDLE constantVS;
2135 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002136 IDirect3DDevice9 *device = getDevice();
2137
2138 if (constantPS)
2139 {
2140 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2141 }
2142
2143 if (constantVS)
2144 {
2145 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2146 }
2147
2148 delete[] vector;
2149
2150 return true;
2151}
2152
2153bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
2154{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002155 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2156
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002157 D3DXHANDLE constantPS;
2158 D3DXHANDLE constantVS;
2159 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002160 IDirect3DDevice9 *device = getDevice();
2161
2162 if (constantPS)
2163 {
2164 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
2165 }
2166
2167 if (constantVS)
2168 {
2169 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
2170 }
2171
2172 return true;
2173}
2174
2175bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
2176{
2177 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2178
2179 for (int i = 0; i < count; i++)
2180 {
2181 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
2182 value[1], value[3], 0, 0,
2183 0, 0, 1, 0,
2184 0, 0, 0, 1);
2185
2186 value += 4;
2187 }
2188
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002189 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2190
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002191 D3DXHANDLE constantPS;
2192 D3DXHANDLE constantVS;
2193 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002194 IDirect3DDevice9 *device = getDevice();
2195
2196 if (constantPS)
2197 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002198 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002199 }
2200
2201 if (constantVS)
2202 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002203 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002204 }
2205
2206 delete[] matrix;
2207
2208 return true;
2209}
2210
2211bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
2212{
2213 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2214
2215 for (int i = 0; i < count; i++)
2216 {
2217 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
2218 value[1], value[4], value[7], 0,
2219 value[2], value[5], value[8], 0,
2220 0, 0, 0, 1);
2221
2222 value += 9;
2223 }
2224
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002225 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2226
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002227 D3DXHANDLE constantPS;
2228 D3DXHANDLE constantVS;
2229 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002230 IDirect3DDevice9 *device = getDevice();
2231
2232 if (constantPS)
2233 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002234 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002235 }
2236
2237 if (constantVS)
2238 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002239 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002240 }
2241
2242 delete[] matrix;
2243
2244 return true;
2245}
2246
2247bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
2248{
2249 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2250
2251 for (int i = 0; i < count; i++)
2252 {
2253 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
2254 value[1], value[5], value[9], value[13],
2255 value[2], value[6], value[10], value[14],
2256 value[3], value[7], value[11], value[15]);
2257
2258 value += 16;
2259 }
2260
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002261 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2262
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002263 D3DXHANDLE constantPS;
2264 D3DXHANDLE constantVS;
2265 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002266 IDirect3DDevice9 *device = getDevice();
2267
2268 if (constantPS)
2269 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002270 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002271 }
2272
2273 if (constantVS)
2274 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002275 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002276 }
2277
2278 delete[] matrix;
2279
2280 return true;
2281}
2282
2283bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
2284{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002285 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2286
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002287 D3DXHANDLE constantPS;
2288 D3DXHANDLE constantVS;
2289 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002290 IDirect3DDevice9 *device = getDevice();
2291
2292 if (constantPS)
2293 {
2294 D3DXCONSTANT_DESC constantDescription;
2295 UINT descriptionCount = 1;
2296 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002297 ASSERT(SUCCEEDED(result));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002298
2299 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2300 {
2301 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
2302
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002303 for (int i = 0; i < count; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002304 {
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002305 unsigned int samplerIndex = firstIndex + i;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002306
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002307 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002308 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002309 ASSERT(mSamplersPS[samplerIndex].active);
2310 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002311 }
2312 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002313 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002314 else
2315 {
2316 mConstantTablePS->SetIntArray(device, constantPS, v, count);
2317 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002318 }
2319
2320 if (constantVS)
2321 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002322 D3DXCONSTANT_DESC constantDescription;
2323 UINT descriptionCount = 1;
2324 HRESULT result = mConstantTableVS->GetConstantDesc(constantVS, &constantDescription, &descriptionCount);
2325 ASSERT(SUCCEEDED(result));
2326
2327 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2328 {
2329 unsigned int firstIndex = mConstantTableVS->GetSamplerIndex(constantVS);
2330
2331 for (int i = 0; i < count; i++)
2332 {
2333 unsigned int samplerIndex = firstIndex + i;
2334
2335 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2336 {
2337 ASSERT(mSamplersVS[samplerIndex].active);
2338 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2339 }
2340 }
2341 }
2342 else
2343 {
2344 mConstantTableVS->SetIntArray(device, constantVS, v, count);
2345 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002346 }
2347
2348 return true;
2349}
2350
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002351bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
2352{
2353 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2354
2355 for (int i = 0; i < count; i++)
2356 {
2357 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2358
2359 v += 2;
2360 }
2361
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002362 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2363
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002364 D3DXHANDLE constantPS;
2365 D3DXHANDLE constantVS;
2366 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002367 IDirect3DDevice9 *device = getDevice();
2368
2369 if (constantPS)
2370 {
2371 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2372 }
2373
2374 if (constantVS)
2375 {
2376 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2377 }
2378
2379 delete[] vector;
2380
2381 return true;
2382}
2383
2384bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
2385{
2386 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2387
2388 for (int i = 0; i < count; i++)
2389 {
2390 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2391
2392 v += 3;
2393 }
2394
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002395 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2396
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002397 D3DXHANDLE constantPS;
2398 D3DXHANDLE constantVS;
2399 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002400 IDirect3DDevice9 *device = getDevice();
2401
2402 if (constantPS)
2403 {
2404 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2405 }
2406
2407 if (constantVS)
2408 {
2409 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2410 }
2411
2412 delete[] vector;
2413
2414 return true;
2415}
2416
2417bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
2418{
2419 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2420
2421 for (int i = 0; i < count; i++)
2422 {
2423 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2424
2425 v += 4;
2426 }
2427
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002428 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2429
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002430 D3DXHANDLE constantPS;
2431 D3DXHANDLE constantVS;
2432 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002433 IDirect3DDevice9 *device = getDevice();
2434
2435 if (constantPS)
2436 {
2437 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2438 }
2439
2440 if (constantVS)
2441 {
2442 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2443 }
2444
2445 delete [] vector;
2446
2447 return true;
2448}
2449
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002450
2451// append a santized message to the program info log.
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002452// The D3D compiler includes a fake file path in some of the warning or error
2453// messages, so lets remove all occurrences of this fake file path from the log.
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002454void Program::appendToInfoLogSanitized(const char *message)
2455{
2456 std::string msg(message);
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002457
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002458 size_t found;
2459 do
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002460 {
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002461 found = msg.find(fakepath);
2462 if (found != std::string::npos)
2463 {
2464 msg.erase(found, strlen(fakepath));
2465 }
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002466 }
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002467 while (found != std::string::npos);
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002468
2469 appendToInfoLog("%s\n", msg.c_str());
2470}
2471
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002472void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002473{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002474 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002475 {
2476 return;
2477 }
2478
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002479 char info[1024];
2480
2481 va_list vararg;
2482 va_start(vararg, format);
2483 vsnprintf(info, sizeof(info), format, vararg);
2484 va_end(vararg);
2485
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002486 size_t infoLength = strlen(info);
2487
2488 if (!mInfoLog)
2489 {
2490 mInfoLog = new char[infoLength + 1];
2491 strcpy(mInfoLog, info);
2492 }
2493 else
2494 {
2495 size_t logLength = strlen(mInfoLog);
2496 char *newLog = new char[logLength + infoLength + 1];
2497 strcpy(newLog, mInfoLog);
2498 strcpy(newLog + logLength, info);
2499
2500 delete[] mInfoLog;
2501 mInfoLog = newLog;
2502 }
2503}
2504
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002505void Program::resetInfoLog()
2506{
2507 if (mInfoLog)
2508 {
2509 delete [] mInfoLog;
daniel@transgaming.com6a20d102010-08-31 13:54:27 +00002510 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002511 }
2512}
2513
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002514// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
2515void Program::unlink(bool destroy)
2516{
2517 if (destroy) // Object being destructed
2518 {
2519 if (mFragmentShader)
2520 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002521 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002522 mFragmentShader = NULL;
2523 }
2524
2525 if (mVertexShader)
2526 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002527 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002528 mVertexShader = NULL;
2529 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002530 }
2531
2532 if (mPixelExecutable)
2533 {
2534 mPixelExecutable->Release();
2535 mPixelExecutable = NULL;
2536 }
2537
2538 if (mVertexExecutable)
2539 {
2540 mVertexExecutable->Release();
2541 mVertexExecutable = NULL;
2542 }
2543
2544 if (mConstantTablePS)
2545 {
2546 mConstantTablePS->Release();
2547 mConstantTablePS = NULL;
2548 }
2549
2550 if (mConstantTableVS)
2551 {
2552 mConstantTableVS->Release();
2553 mConstantTableVS = NULL;
2554 }
2555
2556 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2557 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002558 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002559 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002560 }
2561
2562 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2563 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002564 mSamplersPS[index].active = false;
2565 }
2566
2567 for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
2568 {
2569 mSamplersVS[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002570 }
2571
2572 while (!mUniforms.empty())
2573 {
2574 delete mUniforms.back();
2575 mUniforms.pop_back();
2576 }
2577
daniel@transgaming.com31754962010-11-28 02:02:52 +00002578 mDxDepthRangeLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002579 mDxDepthLocation = -1;
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002580 mDxViewportLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002581 mDxHalfPixelSizeLocation = -1;
2582 mDxFrontCCWLocation = -1;
2583 mDxPointsOrLinesLocation = -1;
2584
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002585 mUniformIndex.clear();
2586
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002587 mPixelHLSL.clear();
2588 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002589
2590 delete[] mInfoLog;
2591 mInfoLog = NULL;
2592
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002593 mLinked = false;
2594}
2595
2596bool Program::isLinked()
2597{
2598 return mLinked;
2599}
2600
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002601bool Program::isValidated() const
2602{
2603 return mValidated;
2604}
2605
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002606void Program::release()
2607{
2608 mRefCount--;
2609
2610 if (mRefCount == 0 && mDeleteStatus)
2611 {
2612 mResourceManager->deleteProgram(mHandle);
2613 }
2614}
2615
2616void Program::addRef()
2617{
2618 mRefCount++;
2619}
2620
2621unsigned int Program::getRefCount() const
2622{
2623 return mRefCount;
2624}
2625
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002626unsigned int Program::getSerial() const
2627{
2628 return mSerial;
2629}
2630
2631unsigned int Program::issueSerial()
2632{
2633 return mCurrentSerial++;
2634}
2635
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002636int Program::getInfoLogLength() const
2637{
2638 if (!mInfoLog)
2639 {
2640 return 0;
2641 }
2642 else
2643 {
2644 return strlen(mInfoLog) + 1;
2645 }
2646}
2647
2648void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2649{
2650 int index = 0;
2651
2652 if (mInfoLog)
2653 {
2654 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2655 {
2656 infoLog[index] = mInfoLog[index];
2657 index++;
2658 }
2659 }
2660
2661 if (bufSize)
2662 {
2663 infoLog[index] = '\0';
2664 }
2665
2666 if (length)
2667 {
2668 *length = index;
2669 }
2670}
2671
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002672void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2673{
2674 int total = 0;
2675
2676 if (mVertexShader)
2677 {
2678 if (total < maxCount)
2679 {
2680 shaders[total] = mVertexShader->getHandle();
2681 }
2682
2683 total++;
2684 }
2685
2686 if (mFragmentShader)
2687 {
2688 if (total < maxCount)
2689 {
2690 shaders[total] = mFragmentShader->getHandle();
2691 }
2692
2693 total++;
2694 }
2695
2696 if (count)
2697 {
2698 *count = total;
2699 }
2700}
2701
daniel@transgaming.com85423182010-04-22 13:35:27 +00002702void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2703{
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002704 // Skip over inactive attributes
2705 unsigned int activeAttribute = 0;
2706 unsigned int attribute;
2707 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
daniel@transgaming.com85423182010-04-22 13:35:27 +00002708 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002709 if (mLinkedAttribute[attribute].name.empty())
daniel@transgaming.com85423182010-04-22 13:35:27 +00002710 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002711 continue;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002712 }
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002713
2714 if (activeAttribute == index)
2715 {
2716 break;
2717 }
2718
2719 activeAttribute++;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002720 }
2721
2722 if (bufsize > 0)
2723 {
2724 const char *string = mLinkedAttribute[attribute].name.c_str();
2725
2726 strncpy(name, string, bufsize);
2727 name[bufsize - 1] = '\0';
2728
2729 if (length)
2730 {
2731 *length = strlen(name);
2732 }
2733 }
2734
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002735 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002736
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002737 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002738}
2739
2740GLint Program::getActiveAttributeCount()
2741{
2742 int count = 0;
2743
2744 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2745 {
2746 if (!mLinkedAttribute[attributeIndex].name.empty())
2747 {
2748 count++;
2749 }
2750 }
2751
2752 return count;
2753}
2754
2755GLint Program::getActiveAttributeMaxLength()
2756{
2757 int maxLength = 0;
2758
2759 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2760 {
2761 if (!mLinkedAttribute[attributeIndex].name.empty())
2762 {
2763 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2764 }
2765 }
2766
2767 return maxLength;
2768}
2769
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002770void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2771{
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002772 // Skip over internal uniforms
2773 unsigned int activeUniform = 0;
2774 unsigned int uniform;
2775 for (uniform = 0; uniform < mUniforms.size(); uniform++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002776 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002777 if (mUniforms[uniform]->name.substr(0, 3) == "dx_")
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002778 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002779 continue;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002780 }
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002781
2782 if (activeUniform == index)
2783 {
2784 break;
2785 }
2786
2787 activeUniform++;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002788 }
2789
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002790 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2791
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002792 if (bufsize > 0)
2793 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002794 std::string string = mUniforms[uniform]->name;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002795
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002796 if (mUniforms[uniform]->isArray())
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002797 {
2798 string += "[0]";
2799 }
2800
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002801 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002802 name[bufsize - 1] = '\0';
2803
2804 if (length)
2805 {
2806 *length = strlen(name);
2807 }
2808 }
2809
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002810 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002811
2812 *type = mUniforms[uniform]->type;
2813}
2814
2815GLint Program::getActiveUniformCount()
2816{
2817 int count = 0;
2818
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002819 unsigned int numUniforms = mUniforms.size();
2820 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002821 {
2822 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2823 {
2824 count++;
2825 }
2826 }
2827
2828 return count;
2829}
2830
2831GLint Program::getActiveUniformMaxLength()
2832{
2833 int maxLength = 0;
2834
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002835 unsigned int numUniforms = mUniforms.size();
2836 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002837 {
2838 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2839 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002840 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2841 if (mUniforms[uniformIndex]->isArray())
zmo@google.com53d73e02011-03-24 21:27:57 +00002842 {
2843 length += 3; // Counting in "[0]".
2844 }
2845 maxLength = std::max(length, maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002846 }
2847 }
2848
2849 return maxLength;
2850}
2851
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002852void Program::flagForDeletion()
2853{
2854 mDeleteStatus = true;
2855}
2856
2857bool Program::isFlaggedForDeletion() const
2858{
2859 return mDeleteStatus;
2860}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002861
2862void Program::validate()
2863{
2864 resetInfoLog();
2865
2866 if (!isLinked())
2867 {
2868 appendToInfoLog("Program has not been successfully linked.");
2869 mValidated = false;
2870 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002871 else
2872 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002873 applyUniforms();
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002874 if (!validateSamplers(true))
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002875 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002876 mValidated = false;
2877 }
2878 else
2879 {
2880 mValidated = true;
2881 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002882 }
2883}
2884
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002885bool Program::validateSamplers(bool logErrors)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002886{
2887 // if any two active samplers in a program are of different types, but refer to the same
2888 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2889 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002890
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002891 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002892 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2893
2894 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2895 {
2896 textureUnitType[i] = TEXTURE_UNKNOWN;
2897 }
2898
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002899 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2900 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002901 if (mSamplersPS[i].active)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002902 {
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002903 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002904
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002905 if (unit >= maxCombinedTextureImageUnits)
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002906 {
2907 if (logErrors)
2908 {
2909 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
2910 }
2911
2912 return false;
2913 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002914
2915 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002916 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002917 if (mSamplersPS[i].textureType != textureUnitType[unit])
2918 {
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002919 if (logErrors)
2920 {
2921 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2922 }
2923
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002924 return false;
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002925 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002926 }
2927 else
2928 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002929 textureUnitType[unit] = mSamplersPS[i].textureType;
2930 }
2931 }
2932 }
2933
2934 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
2935 {
2936 if (mSamplersVS[i].active)
2937 {
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002938 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002939
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002940 if (unit >= maxCombinedTextureImageUnits)
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002941 {
2942 if (logErrors)
2943 {
2944 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
2945 }
2946
2947 return false;
2948 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002949
2950 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2951 {
2952 if (mSamplersVS[i].textureType != textureUnitType[unit])
2953 {
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002954 if (logErrors)
2955 {
2956 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2957 }
2958
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002959 return false;
2960 }
2961 }
2962 else
2963 {
2964 textureUnitType[unit] = mSamplersVS[i].textureType;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002965 }
2966 }
2967 }
2968
2969 return true;
2970}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002971
2972void Program::getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS)
2973{
2974 if (!targetUniform->handlesSet)
2975 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002976 targetUniform->psHandle = mConstantTablePS->GetConstantByName(0, targetUniform->_name.c_str());
2977 targetUniform->vsHandle = mConstantTableVS->GetConstantByName(0, targetUniform->_name.c_str());
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002978 targetUniform->handlesSet = true;
2979 }
2980
2981 *constantPS = targetUniform->psHandle;
2982 *constantVS = targetUniform->vsHandle;
2983}
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002984
daniel@transgaming.com31754962010-11-28 02:02:52 +00002985GLint Program::getDxDepthRangeLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002986{
daniel@transgaming.com31754962010-11-28 02:02:52 +00002987 return mDxDepthRangeLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002988}
2989
2990GLint Program::getDxDepthLocation() const
2991{
2992 return mDxDepthLocation;
2993}
2994
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002995GLint Program::getDxViewportLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002996{
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002997 return mDxViewportLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002998}
2999
3000GLint Program::getDxHalfPixelSizeLocation() const
3001{
3002 return mDxHalfPixelSizeLocation;
3003}
3004
3005GLint Program::getDxFrontCCWLocation() const
3006{
3007 return mDxFrontCCWLocation;
3008}
3009
3010GLint Program::getDxPointsOrLinesLocation() const
3011{
3012 return mDxPointsOrLinesLocation;
3013}
3014
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003015}