blob: 206d62e1cd6339d39a15def9e4090a14868bee8b [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)
daniel@transgaming.comc72c6412011-09-20 16:09:17 +000037 : type(type), _name(_name), name(Program::undecorateUniform(_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{
daniel@transgaming.comc72c6412011-09-20 16:09:17 +000053 return _name.substr(0, 3) == "ar_";
daniel@transgaming.com024f1a92011-09-20 16:06:25 +000054}
55
56UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index)
daniel@transgaming.comc72c6412011-09-20 16:09:17 +000057 : name(Program::undecorateUniform(_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
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001285 mVertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001286
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 {
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001320 mVertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001321
1322 if (VariableRowCount(attribute->type) > 1) // Matrix
1323 {
1324 mVertexHLSL += "transpose";
1325 }
1326
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001327 mVertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001328 }
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.comc72c6412011-09-20 16:09:17 +00001906std::string Program::decorateAttribute(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.comc72c6412011-09-20 16:09:17 +00001916std::string Program::undecorateUniform(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.comc72c6412011-09-20 16:09:17 +00001922 else if (_name.substr(0, 3) == "ar_")
1923 {
1924 return _name.substr(3);
1925 }
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001926
1927 return _name;
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001928}
1929
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001930bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1931{
1932 BOOL *vector = new BOOL[count];
1933 for (int i = 0; i < count; i++)
1934 {
1935 if (v[i] == GL_FALSE)
1936 vector[i] = 0;
1937 else
1938 vector[i] = 1;
1939 }
1940
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001941 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1942
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001943 D3DXHANDLE constantPS;
1944 D3DXHANDLE constantVS;
1945 getConstantHandles(targetUniform, &constantPS, &constantVS);
1946
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001947 IDirect3DDevice9 *device = getDevice();
1948
1949 if (constantPS)
1950 {
1951 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1952 }
1953
1954 if (constantVS)
1955 {
1956 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1957 }
1958
1959 delete [] vector;
1960
1961 return true;
1962}
1963
1964bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1965{
1966 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1967
1968 for (int i = 0; i < count; i++)
1969 {
1970 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1971 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1972
1973 v += 2;
1974 }
1975
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001976 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1977
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00001978 D3DXHANDLE constantPS;
1979 D3DXHANDLE constantVS;
1980 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001981 IDirect3DDevice9 *device = getDevice();
1982
1983 if (constantPS)
1984 {
1985 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1986 }
1987
1988 if (constantVS)
1989 {
1990 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1991 }
1992
1993 delete[] vector;
1994
1995 return true;
1996}
1997
1998bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1999{
2000 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2001
2002 for (int i = 0; i < count; i++)
2003 {
2004 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
2005 (v[1] == GL_FALSE ? 0.0f : 1.0f),
2006 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
2007
2008 v += 3;
2009 }
2010
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002011 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2012
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002013 D3DXHANDLE constantPS;
2014 D3DXHANDLE constantVS;
2015 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002016 IDirect3DDevice9 *device = getDevice();
2017
2018 if (constantPS)
2019 {
2020 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2021 }
2022
2023 if (constantVS)
2024 {
2025 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2026 }
2027
2028 delete[] vector;
2029
2030 return true;
2031}
2032
2033bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
2034{
2035 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2036
2037 for (int i = 0; i < count; i++)
2038 {
2039 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
2040 (v[1] == GL_FALSE ? 0.0f : 1.0f),
2041 (v[2] == GL_FALSE ? 0.0f : 1.0f),
2042 (v[3] == GL_FALSE ? 0.0f : 1.0f));
2043
2044 v += 3;
2045 }
2046
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002047 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2048
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002049 D3DXHANDLE constantPS;
2050 D3DXHANDLE constantVS;
2051 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002052 IDirect3DDevice9 *device = getDevice();
2053
2054 if (constantPS)
2055 {
2056 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2057 }
2058
2059 if (constantVS)
2060 {
2061 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2062 }
2063
2064 delete [] vector;
2065
2066 return true;
2067}
2068
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002069bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
2070{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002071 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2072
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002073 D3DXHANDLE constantPS;
2074 D3DXHANDLE constantVS;
2075 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002076 IDirect3DDevice9 *device = getDevice();
2077
2078 if (constantPS)
2079 {
2080 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
2081 }
2082
2083 if (constantVS)
2084 {
2085 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
2086 }
2087
2088 return true;
2089}
2090
2091bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
2092{
2093 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2094
2095 for (int i = 0; i < count; i++)
2096 {
2097 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
2098
2099 v += 2;
2100 }
2101
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002102 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2103
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002104 D3DXHANDLE constantPS;
2105 D3DXHANDLE constantVS;
2106 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002107 IDirect3DDevice9 *device = getDevice();
2108
2109 if (constantPS)
2110 {
2111 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2112 }
2113
2114 if (constantVS)
2115 {
2116 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2117 }
2118
2119 delete[] vector;
2120
2121 return true;
2122}
2123
2124bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
2125{
2126 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2127
2128 for (int i = 0; i < count; i++)
2129 {
2130 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
2131
2132 v += 3;
2133 }
2134
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002135 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2136
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002137 D3DXHANDLE constantPS;
2138 D3DXHANDLE constantVS;
2139 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002140 IDirect3DDevice9 *device = getDevice();
2141
2142 if (constantPS)
2143 {
2144 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2145 }
2146
2147 if (constantVS)
2148 {
2149 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2150 }
2151
2152 delete[] vector;
2153
2154 return true;
2155}
2156
2157bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
2158{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002159 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2160
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002161 D3DXHANDLE constantPS;
2162 D3DXHANDLE constantVS;
2163 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002164 IDirect3DDevice9 *device = getDevice();
2165
2166 if (constantPS)
2167 {
2168 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
2169 }
2170
2171 if (constantVS)
2172 {
2173 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
2174 }
2175
2176 return true;
2177}
2178
2179bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
2180{
2181 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2182
2183 for (int i = 0; i < count; i++)
2184 {
2185 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
2186 value[1], value[3], 0, 0,
2187 0, 0, 1, 0,
2188 0, 0, 0, 1);
2189
2190 value += 4;
2191 }
2192
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002193 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2194
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002195 D3DXHANDLE constantPS;
2196 D3DXHANDLE constantVS;
2197 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002198 IDirect3DDevice9 *device = getDevice();
2199
2200 if (constantPS)
2201 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002202 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002203 }
2204
2205 if (constantVS)
2206 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002207 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002208 }
2209
2210 delete[] matrix;
2211
2212 return true;
2213}
2214
2215bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
2216{
2217 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2218
2219 for (int i = 0; i < count; i++)
2220 {
2221 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
2222 value[1], value[4], value[7], 0,
2223 value[2], value[5], value[8], 0,
2224 0, 0, 0, 1);
2225
2226 value += 9;
2227 }
2228
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002229 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2230
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002231 D3DXHANDLE constantPS;
2232 D3DXHANDLE constantVS;
2233 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002234 IDirect3DDevice9 *device = getDevice();
2235
2236 if (constantPS)
2237 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002238 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002239 }
2240
2241 if (constantVS)
2242 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002243 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002244 }
2245
2246 delete[] matrix;
2247
2248 return true;
2249}
2250
2251bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
2252{
2253 D3DXMATRIX *matrix = new D3DXMATRIX[count];
2254
2255 for (int i = 0; i < count; i++)
2256 {
2257 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
2258 value[1], value[5], value[9], value[13],
2259 value[2], value[6], value[10], value[14],
2260 value[3], value[7], value[11], value[15]);
2261
2262 value += 16;
2263 }
2264
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002265 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2266
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002267 D3DXHANDLE constantPS;
2268 D3DXHANDLE constantVS;
2269 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002270 IDirect3DDevice9 *device = getDevice();
2271
2272 if (constantPS)
2273 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002274 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002275 }
2276
2277 if (constantVS)
2278 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00002279 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002280 }
2281
2282 delete[] matrix;
2283
2284 return true;
2285}
2286
2287bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
2288{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002289 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2290
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002291 D3DXHANDLE constantPS;
2292 D3DXHANDLE constantVS;
2293 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002294 IDirect3DDevice9 *device = getDevice();
2295
2296 if (constantPS)
2297 {
2298 D3DXCONSTANT_DESC constantDescription;
2299 UINT descriptionCount = 1;
2300 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002301 ASSERT(SUCCEEDED(result));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002302
2303 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2304 {
2305 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
2306
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002307 for (int i = 0; i < count; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002308 {
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002309 unsigned int samplerIndex = firstIndex + i;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002310
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002311 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002312 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002313 ASSERT(mSamplersPS[samplerIndex].active);
2314 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002315 }
2316 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002317 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002318 else
2319 {
2320 mConstantTablePS->SetIntArray(device, constantPS, v, count);
2321 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002322 }
2323
2324 if (constantVS)
2325 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002326 D3DXCONSTANT_DESC constantDescription;
2327 UINT descriptionCount = 1;
2328 HRESULT result = mConstantTableVS->GetConstantDesc(constantVS, &constantDescription, &descriptionCount);
2329 ASSERT(SUCCEEDED(result));
2330
2331 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2332 {
2333 unsigned int firstIndex = mConstantTableVS->GetSamplerIndex(constantVS);
2334
2335 for (int i = 0; i < count; i++)
2336 {
2337 unsigned int samplerIndex = firstIndex + i;
2338
2339 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2340 {
2341 ASSERT(mSamplersVS[samplerIndex].active);
2342 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2343 }
2344 }
2345 }
2346 else
2347 {
2348 mConstantTableVS->SetIntArray(device, constantVS, v, count);
2349 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002350 }
2351
2352 return true;
2353}
2354
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002355bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
2356{
2357 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2358
2359 for (int i = 0; i < count; i++)
2360 {
2361 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2362
2363 v += 2;
2364 }
2365
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002366 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2367
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002368 D3DXHANDLE constantPS;
2369 D3DXHANDLE constantVS;
2370 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002371 IDirect3DDevice9 *device = getDevice();
2372
2373 if (constantPS)
2374 {
2375 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2376 }
2377
2378 if (constantVS)
2379 {
2380 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2381 }
2382
2383 delete[] vector;
2384
2385 return true;
2386}
2387
2388bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
2389{
2390 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2391
2392 for (int i = 0; i < count; i++)
2393 {
2394 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2395
2396 v += 3;
2397 }
2398
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002399 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2400
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002401 D3DXHANDLE constantPS;
2402 D3DXHANDLE constantVS;
2403 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002404 IDirect3DDevice9 *device = getDevice();
2405
2406 if (constantPS)
2407 {
2408 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2409 }
2410
2411 if (constantVS)
2412 {
2413 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2414 }
2415
2416 delete[] vector;
2417
2418 return true;
2419}
2420
2421bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
2422{
2423 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
2424
2425 for (int i = 0; i < count; i++)
2426 {
2427 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2428
2429 v += 4;
2430 }
2431
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002432 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
2433
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002434 D3DXHANDLE constantPS;
2435 D3DXHANDLE constantVS;
2436 getConstantHandles(targetUniform, &constantPS, &constantVS);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002437 IDirect3DDevice9 *device = getDevice();
2438
2439 if (constantPS)
2440 {
2441 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
2442 }
2443
2444 if (constantVS)
2445 {
2446 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
2447 }
2448
2449 delete [] vector;
2450
2451 return true;
2452}
2453
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002454
2455// append a santized message to the program info log.
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002456// The D3D compiler includes a fake file path in some of the warning or error
2457// messages, so lets remove all occurrences of this fake file path from the log.
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002458void Program::appendToInfoLogSanitized(const char *message)
2459{
2460 std::string msg(message);
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002461
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002462 size_t found;
2463 do
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002464 {
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002465 found = msg.find(fakepath);
2466 if (found != std::string::npos)
2467 {
2468 msg.erase(found, strlen(fakepath));
2469 }
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002470 }
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002471 while (found != std::string::npos);
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002472
2473 appendToInfoLog("%s\n", msg.c_str());
2474}
2475
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002476void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002477{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002478 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002479 {
2480 return;
2481 }
2482
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002483 char info[1024];
2484
2485 va_list vararg;
2486 va_start(vararg, format);
2487 vsnprintf(info, sizeof(info), format, vararg);
2488 va_end(vararg);
2489
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002490 size_t infoLength = strlen(info);
2491
2492 if (!mInfoLog)
2493 {
2494 mInfoLog = new char[infoLength + 1];
2495 strcpy(mInfoLog, info);
2496 }
2497 else
2498 {
2499 size_t logLength = strlen(mInfoLog);
2500 char *newLog = new char[logLength + infoLength + 1];
2501 strcpy(newLog, mInfoLog);
2502 strcpy(newLog + logLength, info);
2503
2504 delete[] mInfoLog;
2505 mInfoLog = newLog;
2506 }
2507}
2508
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002509void Program::resetInfoLog()
2510{
2511 if (mInfoLog)
2512 {
2513 delete [] mInfoLog;
daniel@transgaming.com6a20d102010-08-31 13:54:27 +00002514 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002515 }
2516}
2517
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002518// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
2519void Program::unlink(bool destroy)
2520{
2521 if (destroy) // Object being destructed
2522 {
2523 if (mFragmentShader)
2524 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002525 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002526 mFragmentShader = NULL;
2527 }
2528
2529 if (mVertexShader)
2530 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002531 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002532 mVertexShader = NULL;
2533 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002534 }
2535
2536 if (mPixelExecutable)
2537 {
2538 mPixelExecutable->Release();
2539 mPixelExecutable = NULL;
2540 }
2541
2542 if (mVertexExecutable)
2543 {
2544 mVertexExecutable->Release();
2545 mVertexExecutable = NULL;
2546 }
2547
2548 if (mConstantTablePS)
2549 {
2550 mConstantTablePS->Release();
2551 mConstantTablePS = NULL;
2552 }
2553
2554 if (mConstantTableVS)
2555 {
2556 mConstantTableVS->Release();
2557 mConstantTableVS = NULL;
2558 }
2559
2560 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2561 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002562 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002563 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002564 }
2565
2566 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2567 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002568 mSamplersPS[index].active = false;
2569 }
2570
2571 for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
2572 {
2573 mSamplersVS[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002574 }
2575
2576 while (!mUniforms.empty())
2577 {
2578 delete mUniforms.back();
2579 mUniforms.pop_back();
2580 }
2581
daniel@transgaming.com31754962010-11-28 02:02:52 +00002582 mDxDepthRangeLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002583 mDxDepthLocation = -1;
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002584 mDxViewportLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002585 mDxHalfPixelSizeLocation = -1;
2586 mDxFrontCCWLocation = -1;
2587 mDxPointsOrLinesLocation = -1;
2588
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002589 mUniformIndex.clear();
2590
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002591 mPixelHLSL.clear();
2592 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002593
2594 delete[] mInfoLog;
2595 mInfoLog = NULL;
2596
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002597 mLinked = false;
2598}
2599
2600bool Program::isLinked()
2601{
2602 return mLinked;
2603}
2604
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002605bool Program::isValidated() const
2606{
2607 return mValidated;
2608}
2609
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002610void Program::release()
2611{
2612 mRefCount--;
2613
2614 if (mRefCount == 0 && mDeleteStatus)
2615 {
2616 mResourceManager->deleteProgram(mHandle);
2617 }
2618}
2619
2620void Program::addRef()
2621{
2622 mRefCount++;
2623}
2624
2625unsigned int Program::getRefCount() const
2626{
2627 return mRefCount;
2628}
2629
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002630unsigned int Program::getSerial() const
2631{
2632 return mSerial;
2633}
2634
2635unsigned int Program::issueSerial()
2636{
2637 return mCurrentSerial++;
2638}
2639
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002640int Program::getInfoLogLength() const
2641{
2642 if (!mInfoLog)
2643 {
2644 return 0;
2645 }
2646 else
2647 {
2648 return strlen(mInfoLog) + 1;
2649 }
2650}
2651
2652void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2653{
2654 int index = 0;
2655
2656 if (mInfoLog)
2657 {
2658 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2659 {
2660 infoLog[index] = mInfoLog[index];
2661 index++;
2662 }
2663 }
2664
2665 if (bufSize)
2666 {
2667 infoLog[index] = '\0';
2668 }
2669
2670 if (length)
2671 {
2672 *length = index;
2673 }
2674}
2675
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002676void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2677{
2678 int total = 0;
2679
2680 if (mVertexShader)
2681 {
2682 if (total < maxCount)
2683 {
2684 shaders[total] = mVertexShader->getHandle();
2685 }
2686
2687 total++;
2688 }
2689
2690 if (mFragmentShader)
2691 {
2692 if (total < maxCount)
2693 {
2694 shaders[total] = mFragmentShader->getHandle();
2695 }
2696
2697 total++;
2698 }
2699
2700 if (count)
2701 {
2702 *count = total;
2703 }
2704}
2705
daniel@transgaming.com85423182010-04-22 13:35:27 +00002706void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2707{
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002708 // Skip over inactive attributes
2709 unsigned int activeAttribute = 0;
2710 unsigned int attribute;
2711 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
daniel@transgaming.com85423182010-04-22 13:35:27 +00002712 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002713 if (mLinkedAttribute[attribute].name.empty())
daniel@transgaming.com85423182010-04-22 13:35:27 +00002714 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002715 continue;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002716 }
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002717
2718 if (activeAttribute == index)
2719 {
2720 break;
2721 }
2722
2723 activeAttribute++;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002724 }
2725
2726 if (bufsize > 0)
2727 {
2728 const char *string = mLinkedAttribute[attribute].name.c_str();
2729
2730 strncpy(name, string, bufsize);
2731 name[bufsize - 1] = '\0';
2732
2733 if (length)
2734 {
2735 *length = strlen(name);
2736 }
2737 }
2738
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002739 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002740
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002741 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002742}
2743
2744GLint Program::getActiveAttributeCount()
2745{
2746 int count = 0;
2747
2748 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2749 {
2750 if (!mLinkedAttribute[attributeIndex].name.empty())
2751 {
2752 count++;
2753 }
2754 }
2755
2756 return count;
2757}
2758
2759GLint Program::getActiveAttributeMaxLength()
2760{
2761 int maxLength = 0;
2762
2763 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2764 {
2765 if (!mLinkedAttribute[attributeIndex].name.empty())
2766 {
2767 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2768 }
2769 }
2770
2771 return maxLength;
2772}
2773
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002774void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2775{
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002776 // Skip over internal uniforms
2777 unsigned int activeUniform = 0;
2778 unsigned int uniform;
2779 for (uniform = 0; uniform < mUniforms.size(); uniform++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002780 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002781 if (mUniforms[uniform]->name.substr(0, 3) == "dx_")
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002782 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002783 continue;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002784 }
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002785
2786 if (activeUniform == index)
2787 {
2788 break;
2789 }
2790
2791 activeUniform++;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002792 }
2793
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002794 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2795
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002796 if (bufsize > 0)
2797 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002798 std::string string = mUniforms[uniform]->name;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002799
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002800 if (mUniforms[uniform]->isArray())
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002801 {
2802 string += "[0]";
2803 }
2804
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002805 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002806 name[bufsize - 1] = '\0';
2807
2808 if (length)
2809 {
2810 *length = strlen(name);
2811 }
2812 }
2813
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002814 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002815
2816 *type = mUniforms[uniform]->type;
2817}
2818
2819GLint Program::getActiveUniformCount()
2820{
2821 int count = 0;
2822
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002823 unsigned int numUniforms = mUniforms.size();
2824 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002825 {
2826 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2827 {
2828 count++;
2829 }
2830 }
2831
2832 return count;
2833}
2834
2835GLint Program::getActiveUniformMaxLength()
2836{
2837 int maxLength = 0;
2838
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002839 unsigned int numUniforms = mUniforms.size();
2840 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002841 {
2842 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2843 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002844 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2845 if (mUniforms[uniformIndex]->isArray())
zmo@google.com53d73e02011-03-24 21:27:57 +00002846 {
2847 length += 3; // Counting in "[0]".
2848 }
2849 maxLength = std::max(length, maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002850 }
2851 }
2852
2853 return maxLength;
2854}
2855
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002856void Program::flagForDeletion()
2857{
2858 mDeleteStatus = true;
2859}
2860
2861bool Program::isFlaggedForDeletion() const
2862{
2863 return mDeleteStatus;
2864}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002865
2866void Program::validate()
2867{
2868 resetInfoLog();
2869
2870 if (!isLinked())
2871 {
2872 appendToInfoLog("Program has not been successfully linked.");
2873 mValidated = false;
2874 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002875 else
2876 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002877 applyUniforms();
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002878 if (!validateSamplers(true))
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002879 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002880 mValidated = false;
2881 }
2882 else
2883 {
2884 mValidated = true;
2885 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002886 }
2887}
2888
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002889bool Program::validateSamplers(bool logErrors)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002890{
2891 // if any two active samplers in a program are of different types, but refer to the same
2892 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2893 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002894
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002895 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002896 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2897
2898 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2899 {
2900 textureUnitType[i] = TEXTURE_UNKNOWN;
2901 }
2902
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002903 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2904 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002905 if (mSamplersPS[i].active)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002906 {
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002907 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002908
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002909 if (unit >= maxCombinedTextureImageUnits)
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002910 {
2911 if (logErrors)
2912 {
2913 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
2914 }
2915
2916 return false;
2917 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002918
2919 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002920 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002921 if (mSamplersPS[i].textureType != textureUnitType[unit])
2922 {
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002923 if (logErrors)
2924 {
2925 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2926 }
2927
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002928 return false;
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002929 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002930 }
2931 else
2932 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002933 textureUnitType[unit] = mSamplersPS[i].textureType;
2934 }
2935 }
2936 }
2937
2938 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
2939 {
2940 if (mSamplersVS[i].active)
2941 {
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002942 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002943
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002944 if (unit >= maxCombinedTextureImageUnits)
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002945 {
2946 if (logErrors)
2947 {
2948 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
2949 }
2950
2951 return false;
2952 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002953
2954 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2955 {
2956 if (mSamplersVS[i].textureType != textureUnitType[unit])
2957 {
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002958 if (logErrors)
2959 {
2960 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2961 }
2962
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002963 return false;
2964 }
2965 }
2966 else
2967 {
2968 textureUnitType[unit] = mSamplersVS[i].textureType;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002969 }
2970 }
2971 }
2972
2973 return true;
2974}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002975
2976void Program::getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS)
2977{
2978 if (!targetUniform->handlesSet)
2979 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002980 targetUniform->psHandle = mConstantTablePS->GetConstantByName(0, targetUniform->_name.c_str());
2981 targetUniform->vsHandle = mConstantTableVS->GetConstantByName(0, targetUniform->_name.c_str());
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002982 targetUniform->handlesSet = true;
2983 }
2984
2985 *constantPS = targetUniform->psHandle;
2986 *constantVS = targetUniform->vsHandle;
2987}
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002988
daniel@transgaming.com31754962010-11-28 02:02:52 +00002989GLint Program::getDxDepthRangeLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002990{
daniel@transgaming.com31754962010-11-28 02:02:52 +00002991 return mDxDepthRangeLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002992}
2993
2994GLint Program::getDxDepthLocation() const
2995{
2996 return mDxDepthLocation;
2997}
2998
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00002999GLint Program::getDxViewportLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00003000{
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +00003001 return mDxViewportLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00003002}
3003
3004GLint Program::getDxHalfPixelSizeLocation() const
3005{
3006 return mDxHalfPixelSizeLocation;
3007}
3008
3009GLint Program::getDxFrontCCWLocation() const
3010{
3011 return mDxFrontCCWLocation;
3012}
3013
3014GLint Program::getDxPointsOrLinesLocation() const
3015{
3016 return mDxPointsOrLinesLocation;
3017}
3018
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003019}