blob: e0fe8d70984ecd324dcf059e38b240a1115e3417 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
daniel@transgaming.comcde6a612012-02-17 18:01:10 +00002// Copyright (c) 2002-2012 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];
kbr@chromium.orgddb6e8e2012-04-25 00:48:13 +000032 snprintf(buffer, sizeof(buffer), "%d", i);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000033 return buffer;
34}
35
apatrick@chromium.org9a30b092012-06-06 20:21:55 +000036AttributeBindings::AttributeBindings()
37{
38}
39
40AttributeBindings::~AttributeBindings()
41{
42}
43
daniel@transgaming.com024f1a92011-09-20 16:06:25 +000044Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize)
daniel@transgaming.comc72c6412011-09-20 16:09:17 +000045 : type(type), _name(_name), name(Program::undecorateUniform(_name)), arraySize(arraySize)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000046{
daniel@transgaming.come918ea22011-11-12 03:15:28 +000047 int bytes = UniformInternalSize(type) * arraySize;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000048 data = new unsigned char[bytes];
49 memset(data, 0, bytes);
50 dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000051}
52
53Uniform::~Uniform()
54{
55 delete[] data;
56}
57
daniel@transgaming.com024f1a92011-09-20 16:06:25 +000058bool Uniform::isArray()
59{
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +000060 return _name.compare(0, 3, "ar_") == 0;
daniel@transgaming.com024f1a92011-09-20 16:06:25 +000061}
62
63UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index)
daniel@transgaming.comc72c6412011-09-20 16:09:17 +000064 : name(Program::undecorateUniform(_name)), element(element), index(index)
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +000065{
66}
67
daniel@transgaming.com73a5db62010-10-15 17:58:13 +000068Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000069{
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +000070 mDevice = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000071 mFragmentShader = NULL;
72 mVertexShader = NULL;
73
74 mPixelExecutable = NULL;
75 mVertexExecutable = NULL;
76 mConstantTablePS = NULL;
77 mConstantTableVS = NULL;
78
daniel@transgaming.comcba50572010-03-28 19:36:09 +000079 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +000080 mValidated = false;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000081
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000082 unlink();
83
84 mDeleteStatus = false;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000085
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000086 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000087}
88
89Program::~Program()
90{
91 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000092
93 if (mVertexShader != NULL)
94 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000095 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000096 }
97
98 if (mFragmentShader != NULL)
99 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000100 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000101 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000102}
103
104bool Program::attachShader(Shader *shader)
105{
106 if (shader->getType() == GL_VERTEX_SHADER)
107 {
108 if (mVertexShader)
109 {
110 return false;
111 }
112
113 mVertexShader = (VertexShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000114 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000115 }
116 else if (shader->getType() == GL_FRAGMENT_SHADER)
117 {
118 if (mFragmentShader)
119 {
120 return false;
121 }
122
123 mFragmentShader = (FragmentShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000124 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000125 }
126 else UNREACHABLE();
127
128 return true;
129}
130
131bool Program::detachShader(Shader *shader)
132{
133 if (shader->getType() == GL_VERTEX_SHADER)
134 {
135 if (mVertexShader != shader)
136 {
137 return false;
138 }
139
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000140 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000141 mVertexShader = NULL;
142 }
143 else if (shader->getType() == GL_FRAGMENT_SHADER)
144 {
145 if (mFragmentShader != shader)
146 {
147 return false;
148 }
149
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000150 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151 mFragmentShader = NULL;
152 }
153 else UNREACHABLE();
154
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000155 return true;
156}
157
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000158int Program::getAttachedShadersCount() const
159{
160 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
161}
162
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000163IDirect3DPixelShader9 *Program::getPixelShader()
164{
165 return mPixelExecutable;
166}
167
168IDirect3DVertexShader9 *Program::getVertexShader()
169{
170 return mVertexExecutable;
171}
172
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000173void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
174{
175 if (index < MAX_VERTEX_ATTRIBS)
176 {
177 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
178 {
179 mAttributeBinding[i].erase(name);
180 }
181
182 mAttributeBinding[index].insert(name);
183 }
184}
185
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000186void Program::bindAttributeLocation(GLuint index, const char *name)
187{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000188 mAttributeBindings.bindAttributeLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000189}
190
191GLuint Program::getAttributeLocation(const char *name)
192{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000193 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000194 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000195 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000197 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000198 {
199 return index;
200 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000201 }
202 }
203
204 return -1;
205}
206
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000207int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000208{
daniel@transgaming.com733ba932011-04-14 15:03:48 +0000209 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
210
211 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000212}
213
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +0000214// Returns one more than the highest sampler index used.
215GLint Program::getUsedSamplerRange(SamplerType type)
216{
217 switch (type)
218 {
219 case SAMPLER_PIXEL:
220 return mUsedPixelSamplerRange;
221 case SAMPLER_VERTEX:
222 return mUsedVertexSamplerRange;
223 default:
224 UNREACHABLE();
225 return 0;
226 }
227}
228
daniel@transgaming.com9ba680a2011-05-11 15:37:11 +0000229// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
230// index (0-15 for the pixel shader and 0-3 for the vertex shader).
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000231GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000232{
jbauman@chromium.org8b3c1af2011-10-12 01:21:41 +0000233 GLint logicalTextureUnit = -1;
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000234
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000235 switch (type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000236 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000237 case SAMPLER_PIXEL:
238 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
239
240 if (mSamplersPS[samplerIndex].active)
241 {
242 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
243 }
244 break;
245 case SAMPLER_VERTEX:
246 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
247
248 if (mSamplersVS[samplerIndex].active)
249 {
250 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
251 }
252 break;
253 default: UNREACHABLE();
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000254 }
255
jbauman@chromium.org8b3c1af2011-10-12 01:21:41 +0000256 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)getContext()->getMaximumCombinedTextureImageUnits())
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000257 {
258 return logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259 }
260
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000261 return -1;
262}
263
daniel@transgaming.com9ba680a2011-05-11 15:37:11 +0000264// Returns the texture type for a given Direct3D 9 sampler type and
265// index (0-15 for the pixel shader and 0-3 for the vertex shader).
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000266TextureType Program::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000267{
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000268 switch (type)
269 {
270 case SAMPLER_PIXEL:
271 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
272 ASSERT(mSamplersPS[samplerIndex].active);
273 return mSamplersPS[samplerIndex].textureType;
274 case SAMPLER_VERTEX:
275 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
276 ASSERT(mSamplersVS[samplerIndex].active);
277 return mSamplersVS[samplerIndex].textureType;
278 default: UNREACHABLE();
279 }
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000280
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000281 return TEXTURE_2D;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000282}
283
daniel@transgaming.com024f1a92011-09-20 16:06:25 +0000284GLint Program::getUniformLocation(std::string name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000285{
apatrick@chromium.orga1d80592012-01-25 21:52:10 +0000286 unsigned int subscript = 0;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000287
daniel@transgaming.comce864422010-11-18 13:16:49 +0000288 // Strip any trailing array operator and retrieve the subscript
daniel@transgaming.com024f1a92011-09-20 16:06:25 +0000289 size_t open = name.find_last_of('[');
290 size_t close = name.find_last_of(']');
291 if (open != std::string::npos && close == name.length() - 1)
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000292 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +0000293 subscript = atoi(name.substr(open + 1).c_str());
294 name.erase(open);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000295 }
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000296
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000297 unsigned int numUniforms = mUniformIndex.size();
298 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000299 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +0000300 if (mUniformIndex[location].name == name &&
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000301 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000302 {
303 return location;
304 }
305 }
306
307 return -1;
308}
309
310bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
311{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000312 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000313 {
314 return false;
315 }
316
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000317 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000318 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000319
320 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000321 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000322 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000323
324 if (arraySize == 1 && count > 1)
325 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
326
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000327 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000328
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000329 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
330
331 for (int i = 0; i < count; i++)
332 {
333 target[0] = v[0];
334 target[1] = 0;
335 target[2] = 0;
336 target[3] = 0;
337 target += 4;
338 v += 1;
339 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000340 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000341 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000342 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000343 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000344
345 if (arraySize == 1 && count > 1)
346 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000347
348 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000349 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000350
351 for (int i = 0; i < count; ++i)
352 {
353 if (v[i] == 0.0f)
354 {
355 boolParams[i] = GL_FALSE;
356 }
357 else
358 {
359 boolParams[i] = GL_TRUE;
360 }
361 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000362 }
363 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000364 {
365 return false;
366 }
367
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000368 return true;
369}
370
371bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
372{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000373 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000374 {
375 return false;
376 }
377
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000378 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000379 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000380
381 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000382 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000383 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000384
385 if (arraySize == 1 && count > 1)
386 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
387
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000388 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000389
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000390 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
391
392 for (int i = 0; i < count; i++)
393 {
394 target[0] = v[0];
395 target[1] = v[1];
396 target[2] = 0;
397 target[3] = 0;
398 target += 4;
399 v += 2;
400 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000401 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000402 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000403 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000404 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000405
406 if (arraySize == 1 && count > 1)
407 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
408
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000409 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
410
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000411 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000412
413 for (int i = 0; i < count * 2; ++i)
414 {
415 if (v[i] == 0.0f)
416 {
417 boolParams[i] = GL_FALSE;
418 }
419 else
420 {
421 boolParams[i] = GL_TRUE;
422 }
423 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000424 }
425 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000426 {
427 return false;
428 }
429
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000430 return true;
431}
432
433bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
434{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000435 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000436 {
437 return false;
438 }
439
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000440 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000441 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000442
443 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000444 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000445 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000446
447 if (arraySize == 1 && count > 1)
448 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
449
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000450 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000451
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000452 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
453
454 for (int i = 0; i < count; i++)
455 {
456 target[0] = v[0];
457 target[1] = v[1];
458 target[2] = v[2];
459 target[3] = 0;
460 target += 4;
461 v += 3;
462 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000463 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000464 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000465 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000466 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000467
468 if (arraySize == 1 && count > 1)
469 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
470
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000471 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000472 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000473
474 for (int i = 0; i < count * 3; ++i)
475 {
476 if (v[i] == 0.0f)
477 {
478 boolParams[i] = GL_FALSE;
479 }
480 else
481 {
482 boolParams[i] = GL_TRUE;
483 }
484 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000485 }
486 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000487 {
488 return false;
489 }
490
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000491 return true;
492}
493
494bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
495{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000496 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000497 {
498 return false;
499 }
500
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000501 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000502 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000503
504 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000505 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000506 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000507
508 if (arraySize == 1 && count > 1)
509 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
510
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000511 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000512
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000513 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
514 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000515 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000516 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000517 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000518 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000519
520 if (arraySize == 1 && count > 1)
521 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
522
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000523 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000524 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000525
526 for (int i = 0; i < count * 4; ++i)
527 {
528 if (v[i] == 0.0f)
529 {
530 boolParams[i] = GL_FALSE;
531 }
532 else
533 {
534 boolParams[i] = GL_TRUE;
535 }
536 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000537 }
538 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000539 {
540 return false;
541 }
542
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000543 return true;
544}
545
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000546template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
547void transposeMatrix(T *target, const GLfloat *value)
548{
549 int copyWidth = std::min(targetWidth, srcWidth);
550 int copyHeight = std::min(targetHeight, srcHeight);
551
552 for (int x = 0; x < copyWidth; x++)
553 {
554 for (int y = 0; y < copyHeight; y++)
555 {
daniel@transgaming.comc9d81a22011-11-12 03:14:30 +0000556 target[x * targetWidth + y] = (T)value[y * srcWidth + x];
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000557 }
558 }
559 // clear unfilled right side
560 for (int y = 0; y < copyHeight; y++)
561 {
562 for (int x = srcWidth; x < targetWidth; x++)
563 {
daniel@transgaming.comc9d81a22011-11-12 03:14:30 +0000564 target[y * targetWidth + x] = (T)0;
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000565 }
566 }
567 // clear unfilled bottom.
568 for (int y = srcHeight; y < targetHeight; y++)
569 {
570 for (int x = 0; x < targetWidth; x++)
571 {
daniel@transgaming.comc9d81a22011-11-12 03:14:30 +0000572 target[y * targetWidth + x] = (T)0;
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000573 }
574 }
575}
576
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000577bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
578{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000579 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000580 {
581 return false;
582 }
583
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000584 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000585 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000586
587 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000588 {
589 return false;
590 }
591
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000592 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000593
594 if (arraySize == 1 && count > 1)
595 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
596
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000597 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000598
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000599 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
600 for (int i = 0; i < count; i++)
601 {
602 transposeMatrix<GLfloat,4,2,2,2>(target, value);
603 target += 8;
604 value += 4;
605 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000606
607 return true;
608}
609
610bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
611{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000612 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000613 {
614 return false;
615 }
616
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000617 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000618 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000619
620 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000621 {
622 return false;
623 }
624
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000625 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000626
627 if (arraySize == 1 && count > 1)
628 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
629
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000630 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000631
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000632 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
633 for (int i = 0; i < count; i++)
634 {
635 transposeMatrix<GLfloat,4,3,3,3>(target, value);
636 target += 12;
637 value += 9;
638 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000639
640 return true;
641}
642
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000643
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000644bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
645{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000646 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000647 {
648 return false;
649 }
650
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000651 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000652 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000653
654 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000655 {
656 return false;
657 }
658
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000659 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000660
661 if (arraySize == 1 && count > 1)
662 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
663
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000664 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000665
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000666 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
667 for (int i = 0; i < count; i++)
668 {
669 transposeMatrix<GLfloat,4,4,4,4>(target, value);
670 target += 16;
671 value += 16;
672 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000673
674 return true;
675}
676
677bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
678{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000679 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000680 {
681 return false;
682 }
683
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000684 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000685 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000686
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000687 if (targetUniform->type == GL_INT ||
688 targetUniform->type == GL_SAMPLER_2D ||
689 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000690 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000691 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000692
693 if (arraySize == 1 && count > 1)
694 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
695
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000696 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000697
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000698 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
699 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000700 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000701 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000702 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000703 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000704
705 if (arraySize == 1 && count > 1)
706 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
707
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000708 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000709 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000710
711 for (int i = 0; i < count; ++i)
712 {
713 if (v[i] == 0)
714 {
715 boolParams[i] = GL_FALSE;
716 }
717 else
718 {
719 boolParams[i] = GL_TRUE;
720 }
721 }
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000722 }
723 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000724 {
725 return false;
726 }
727
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000728 return true;
729}
730
731bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
732{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000733 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000734 {
735 return false;
736 }
737
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000738 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000739 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000740
741 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000742 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000743 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000744
745 if (arraySize == 1 && count > 1)
746 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
747
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000748 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000749
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000750 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
751 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000752 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000753 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000754 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000755 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000756
757 if (arraySize == 1 && count > 1)
758 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
759
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000760 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000761 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000762
763 for (int i = 0; i < count * 2; ++i)
764 {
765 if (v[i] == 0)
766 {
767 boolParams[i] = GL_FALSE;
768 }
769 else
770 {
771 boolParams[i] = GL_TRUE;
772 }
773 }
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000774 }
775 else
776 {
777 return false;
778 }
779
780 return true;
781}
782
783bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
784{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000785 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000786 {
787 return false;
788 }
789
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000790 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000791 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000792
793 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000794 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000795 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000796
797 if (arraySize == 1 && count > 1)
798 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
799
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000800 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000801
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000802 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
803 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000804 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000805 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000806 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000807 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000808
809 if (arraySize == 1 && count > 1)
810 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
811
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000812 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000813 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000814
815 for (int i = 0; i < count * 3; ++i)
816 {
817 if (v[i] == 0)
818 {
819 boolParams[i] = GL_FALSE;
820 }
821 else
822 {
823 boolParams[i] = GL_TRUE;
824 }
825 }
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000826 }
827 else
828 {
829 return false;
830 }
831
832 return true;
833}
834
835bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
836{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000837 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000838 {
839 return false;
840 }
841
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000842 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000843 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000844
845 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000846 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000847 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000848
849 if (arraySize == 1 && count > 1)
850 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
851
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000852 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000853
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000854 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
855 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000856 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000857 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000858 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000859 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000860
861 if (arraySize == 1 && count > 1)
862 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
863
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000864 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000865 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000866
867 for (int i = 0; i < count * 4; ++i)
868 {
869 if (v[i] == 0)
870 {
871 boolParams[i] = GL_FALSE;
872 }
873 else
874 {
875 boolParams[i] = GL_TRUE;
876 }
877 }
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000878 }
879 else
880 {
881 return false;
882 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000883
884 return true;
885}
886
daniel@transgaming.com9a849122011-11-12 03:18:00 +0000887bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000888{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000889 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000890 {
891 return false;
892 }
893
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000894 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000895
daniel@transgaming.com9a849122011-11-12 03:18:00 +0000896 // sized queries -- ensure the provided buffer is large enough
897 if (bufSize)
898 {
899 int requiredBytes = UniformExternalSize(targetUniform->type);
900 if (*bufSize < requiredBytes)
901 {
902 return false;
903 }
904 }
905
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000906 switch (targetUniform->type)
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000907 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000908 case GL_FLOAT_MAT2:
909 transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
910 break;
911 case GL_FLOAT_MAT3:
912 transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
913 break;
914 case GL_FLOAT_MAT4:
915 transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
916 break;
917 default:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000918 {
daniel@transgaming.comedc31502011-11-12 03:14:56 +0000919 unsigned int count = UniformExternalComponentCount(targetUniform->type);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000920 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000921
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000922 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000923 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000924 case GL_BOOL:
925 {
926 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * internalCount;
927
928 for (unsigned int i = 0; i < count; ++i)
929 {
930 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
931 }
932 }
933 break;
934 case GL_FLOAT:
935 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLfloat),
936 count * sizeof(GLfloat));
937 break;
938 case GL_INT:
939 {
940 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * internalCount;
941
942 for (unsigned int i = 0; i < count; ++i)
943 {
944 params[i] = (float)intParams[i];
945 }
946 }
947 break;
948 default: UNREACHABLE();
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000949 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000950 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000951 }
952
953 return true;
954}
955
daniel@transgaming.com9a849122011-11-12 03:18:00 +0000956bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000957{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000958 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000959 {
960 return false;
961 }
962
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000963 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000964
daniel@transgaming.com9a849122011-11-12 03:18:00 +0000965 // sized queries -- ensure the provided buffer is large enough
966 if (bufSize)
967 {
968 int requiredBytes = UniformExternalSize(targetUniform->type);
969 if (*bufSize < requiredBytes)
970 {
971 return false;
972 }
973 }
974
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000975 switch (targetUniform->type)
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000976 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000977 case GL_FLOAT_MAT2:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000978 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000979 transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000980 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000981 break;
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000982 case GL_FLOAT_MAT3:
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000983 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000984 transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000985 }
986 break;
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000987 case GL_FLOAT_MAT4:
988 {
989 transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
990 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000991 break;
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000992 default:
993 {
daniel@transgaming.comedc31502011-11-12 03:14:56 +0000994 unsigned int count = UniformExternalComponentCount(targetUniform->type);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000995 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
996
997 switch (UniformComponentType(targetUniform->type))
998 {
999 case GL_BOOL:
1000 {
1001 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * internalCount;
1002
1003 for (unsigned int i = 0; i < count; ++i)
1004 {
1005 params[i] = (GLint)boolParams[i];
1006 }
1007 }
1008 break;
1009 case GL_FLOAT:
1010 {
1011 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * internalCount;
1012
1013 for (unsigned int i = 0; i < count; ++i)
1014 {
1015 params[i] = (GLint)floatParams[i];
1016 }
1017 }
1018 break;
1019 case GL_INT:
1020 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLint),
1021 count * sizeof(GLint));
1022 break;
1023 default: UNREACHABLE();
1024 }
1025 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +00001026 }
1027
1028 return true;
1029}
1030
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00001031void Program::dirtyAllUniforms()
1032{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00001033 unsigned int numUniforms = mUniforms.size();
1034 for (unsigned int index = 0; index < numUniforms; index++)
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00001035 {
1036 mUniforms[index]->dirty = true;
1037 }
1038}
1039
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001040// Applies all the uniforms set for this program object to the Direct3D 9 device
1041void Program::applyUniforms()
1042{
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00001043 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) {
1044 Uniform *targetUniform = *ub;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001045
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00001046 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001047 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00001048 int arraySize = targetUniform->arraySize;
1049 GLfloat *f = (GLfloat*)targetUniform->data;
1050 GLint *i = (GLint*)targetUniform->data;
1051 GLboolean *b = (GLboolean*)targetUniform->data;
1052
1053 switch (targetUniform->type)
1054 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00001055 case GL_BOOL: applyUniformnbv(targetUniform, arraySize, 1, b); break;
1056 case GL_BOOL_VEC2: applyUniformnbv(targetUniform, arraySize, 2, b); break;
1057 case GL_BOOL_VEC3: applyUniformnbv(targetUniform, arraySize, 3, b); break;
1058 case GL_BOOL_VEC4: applyUniformnbv(targetUniform, arraySize, 4, b); break;
1059 case GL_FLOAT:
1060 case GL_FLOAT_VEC2:
1061 case GL_FLOAT_VEC3:
1062 case GL_FLOAT_VEC4:
1063 case GL_FLOAT_MAT2:
1064 case GL_FLOAT_MAT3:
1065 case GL_FLOAT_MAT4: applyUniformnfv(targetUniform, f); break;
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001066 case GL_SAMPLER_2D:
1067 case GL_SAMPLER_CUBE:
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00001068 case GL_INT: applyUniform1iv(targetUniform, arraySize, i); break;
1069 case GL_INT_VEC2: applyUniform2iv(targetUniform, arraySize, i); break;
1070 case GL_INT_VEC3: applyUniform3iv(targetUniform, arraySize, i); break;
1071 case GL_INT_VEC4: applyUniform4iv(targetUniform, arraySize, i); break;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00001072 default:
1073 UNREACHABLE();
1074 }
1075
1076 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001077 }
1078 }
1079}
1080
1081// Compiles the HLSL code of the attached shaders into executable binaries
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001082ID3D10Blob *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001083{
1084 if (!hlsl)
1085 {
1086 return NULL;
1087 }
1088
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001089 DWORD result;
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001090 UINT flags = 0;
1091 std::string sourceText;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001092 if (perfActive())
1093 {
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001094 flags |= D3DCOMPILE_DEBUG;
1095#ifdef NDEBUG
1096 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1097#else
1098 flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001099#endif
1100
1101 std::string sourcePath = getTempPath();
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001102 sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001103 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001104 }
1105 else
1106 {
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001107 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1108 sourceText = hlsl;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001109 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001110
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001111 ID3D10Blob *binary = NULL;
1112 ID3D10Blob *errorMessage = NULL;
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00001113 result = D3DCompile(hlsl, strlen(hlsl), fakepath, NULL, NULL, "main", profile, flags, 0, &binary, &errorMessage);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001114
1115 if (errorMessage)
1116 {
1117 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001118
daniel@transgaming.com87891f72011-06-01 15:28:35 +00001119 appendToInfoLogSanitized(message);
daniel@transgaming.com0599dc62010-03-21 04:31:36 +00001120 TRACE("\n%s", hlsl);
1121 TRACE("\n%s", message);
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001122
1123 errorMessage->Release();
1124 errorMessage = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001125 }
1126
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001127 if (FAILED(result))
1128 {
1129 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1130 {
1131 error(GL_OUT_OF_MEMORY);
1132 }
1133
1134 return NULL;
1135 }
1136
1137 result = D3DXGetShaderConstantTable(static_cast<const DWORD*>(binary->GetBufferPointer()), constantTable);
1138
1139 if (FAILED(result))
1140 {
1141 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1142 {
1143 error(GL_OUT_OF_MEMORY);
1144 }
1145
1146 binary->Release();
1147
1148 return NULL;
1149 }
1150
1151 return binary;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001152}
1153
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001154// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1155// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001156int Program::packVaryings(const Varying *packing[][4], FragmentShader *fragmentShader)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001157{
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001158 Context *context = getContext();
1159 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1160
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001161 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001162 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001163 int n = VariableRowCount(varying->type) * varying->size;
1164 int m = VariableColumnCount(varying->type);
1165 bool success = false;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001166
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001167 if (m == 2 || m == 3 || m == 4)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001168 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001169 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001170 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001171 bool available = true;
1172
1173 for (int y = 0; y < n && available; y++)
1174 {
1175 for (int x = 0; x < m && available; x++)
1176 {
1177 if (packing[r + y][x])
1178 {
1179 available = false;
1180 }
1181 }
1182 }
1183
1184 if (available)
1185 {
1186 varying->reg = r;
1187 varying->col = 0;
1188
1189 for (int y = 0; y < n; y++)
1190 {
1191 for (int x = 0; x < m; x++)
1192 {
1193 packing[r + y][x] = &*varying;
1194 }
1195 }
1196
1197 success = true;
1198 }
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001199 }
1200
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001201 if (!success && m == 2)
1202 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001203 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001204 {
1205 bool available = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001206
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001207 for (int y = 0; y < n && available; y++)
1208 {
1209 for (int x = 2; x < 4 && available; x++)
1210 {
1211 if (packing[r + y][x])
1212 {
1213 available = false;
1214 }
1215 }
1216 }
1217
1218 if (available)
1219 {
1220 varying->reg = r;
1221 varying->col = 2;
1222
1223 for (int y = 0; y < n; y++)
1224 {
1225 for (int x = 2; x < 4; x++)
1226 {
1227 packing[r + y][x] = &*varying;
1228 }
1229 }
1230
1231 success = true;
1232 }
1233 }
1234 }
1235 }
1236 else if (m == 1)
1237 {
1238 int space[4] = {0};
1239
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001240 for (int y = 0; y < maxVaryingVectors; y++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001241 {
1242 for (int x = 0; x < 4; x++)
1243 {
1244 space[x] += packing[y][x] ? 0 : 1;
1245 }
1246 }
1247
1248 int column = 0;
1249
1250 for (int x = 0; x < 4; x++)
1251 {
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001252 if (space[x] >= n && space[x] < space[column])
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001253 {
1254 column = x;
1255 }
1256 }
1257
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001258 if (space[column] >= n)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001259 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001260 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001261 {
1262 if (!packing[r][column])
1263 {
1264 varying->reg = r;
1265
1266 for (int y = r; y < r + n; y++)
1267 {
1268 packing[y][column] = &*varying;
1269 }
1270
1271 break;
1272 }
1273 }
1274
1275 varying->col = column;
1276
1277 success = true;
1278 }
1279 }
1280 else UNREACHABLE();
1281
1282 if (!success)
1283 {
1284 appendToInfoLog("Could not pack varying %s", varying->name.c_str());
1285
1286 return -1;
1287 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001288 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001289
1290 // Return the number of used registers
1291 int registers = 0;
1292
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001293 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001294 {
1295 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1296 {
1297 registers++;
1298 }
1299 }
1300
1301 return registers;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001302}
1303
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001304bool Program::linkVaryings(std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001305{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001306 if (pixelHLSL.empty() || vertexHLSL.empty())
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001307 {
1308 return false;
1309 }
1310
daniel@transgaming.com97750022011-02-11 13:23:13 +00001311 // Reset the varying register assignments
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001312 for (VaryingList::iterator fragVar = fragmentShader->mVaryings.begin(); fragVar != fragmentShader->mVaryings.end(); fragVar++)
daniel@transgaming.com97750022011-02-11 13:23:13 +00001313 {
1314 fragVar->reg = -1;
1315 fragVar->col = -1;
1316 }
1317
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001318 for (VaryingList::iterator vtxVar = vertexShader->mVaryings.begin(); vtxVar != vertexShader->mVaryings.end(); vtxVar++)
daniel@transgaming.com97750022011-02-11 13:23:13 +00001319 {
1320 vtxVar->reg = -1;
1321 vtxVar->col = -1;
1322 }
1323
1324 // Map the varyings to the register file
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001325 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001326 int registers = packVaryings(packing, fragmentShader);
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001327
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001328 if (registers < 0)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001329 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001330 return false;
1331 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001332
daniel@transgaming.com97750022011-02-11 13:23:13 +00001333 // Write the HLSL input/output declarations
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001334 Context *context = getContext();
1335 const bool sm3 = context->supportsShaderModel3();
1336 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1337
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001338 if (registers == maxVaryingVectors && fragmentShader->mUsesFragCoord)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001339 {
1340 appendToInfoLog("No varying registers left to support gl_FragCoord");
1341
1342 return false;
1343 }
1344
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001345 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001346 {
1347 bool matched = false;
1348
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001349 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001350 {
1351 if (output->name == input->name)
1352 {
1353 if (output->type != input->type || output->size != input->size)
1354 {
1355 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
1356
1357 return false;
1358 }
1359
1360 output->reg = input->reg;
1361 output->col = input->col;
1362
1363 matched = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001364 break;
1365 }
1366 }
1367
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001368 if (!matched)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001369 {
daniel@transgaming.com97750022011-02-11 13:23:13 +00001370 appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001371
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001372 return false;
1373 }
1374 }
1375
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001376 std::string varyingSemantic = (sm3 ? "COLOR" : "TEXCOORD");
1377
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001378 vertexHLSL += "struct VS_INPUT\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001379 "{\n";
1380
1381 int semanticIndex = 0;
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001382 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001383 {
1384 switch (attribute->type)
1385 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001386 case GL_FLOAT: vertexHLSL += " float "; break;
1387 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1388 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1389 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1390 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1391 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1392 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001393 default: UNREACHABLE();
1394 }
1395
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001396 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001397
1398 semanticIndex += VariableRowCount(attribute->type);
1399 }
1400
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001401 vertexHLSL += "};\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001402 "\n"
1403 "struct VS_OUTPUT\n"
1404 "{\n"
1405 " float4 gl_Position : POSITION;\n";
1406
1407 for (int r = 0; r < registers; r++)
1408 {
1409 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1410
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001411 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001412 }
1413
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001414 if (fragmentShader->mUsesFragCoord)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001415 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001416 vertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001417 }
1418
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001419 if (vertexShader->mUsesPointSize && sm3)
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001420 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001421 vertexHLSL += " float gl_PointSize : PSIZE;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001422 }
1423
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001424 vertexHLSL += "};\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001425 "\n"
1426 "VS_OUTPUT main(VS_INPUT input)\n"
1427 "{\n";
1428
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001429 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001430 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001431 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001432
1433 if (VariableRowCount(attribute->type) > 1) // Matrix
1434 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001435 vertexHLSL += "transpose";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001436 }
1437
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001438 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001439 }
1440
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001441 vertexHLSL += "\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001442 " gl_main();\n"
1443 "\n"
1444 " VS_OUTPUT output;\n"
1445 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001446 " output.gl_Position.y = gl_Position.y - dx_HalfPixelSize.y * gl_Position.w;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001447 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1448 " output.gl_Position.w = gl_Position.w;\n";
1449
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001450 if (vertexShader->mUsesPointSize && sm3)
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001451 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001452 vertexHLSL += " output.gl_PointSize = clamp(gl_PointSize, 1.0, " + str((int)ALIASED_POINT_SIZE_RANGE_MAX_SM3) + ");\n";
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001453 }
1454
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001455 if (fragmentShader->mUsesFragCoord)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001456 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001457 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001458 }
1459
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001460 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001461 {
1462 if (varying->reg >= 0)
1463 {
1464 for (int i = 0; i < varying->size; i++)
1465 {
1466 int rows = VariableRowCount(varying->type);
1467
1468 for (int j = 0; j < rows; j++)
1469 {
1470 int r = varying->reg + i * rows + j;
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001471 vertexHLSL += " output.v" + str(r);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001472
1473 bool sharedRegister = false; // Register used by multiple varyings
1474
1475 for (int x = 0; x < 4; x++)
1476 {
1477 if (packing[r][x] && packing[r][x] != packing[r][0])
1478 {
1479 sharedRegister = true;
1480 break;
1481 }
1482 }
1483
1484 if(sharedRegister)
1485 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001486 vertexHLSL += ".";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001487
1488 for (int x = 0; x < 4; x++)
1489 {
1490 if (packing[r][x] == &*varying)
1491 {
1492 switch(x)
1493 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001494 case 0: vertexHLSL += "x"; break;
1495 case 1: vertexHLSL += "y"; break;
1496 case 2: vertexHLSL += "z"; break;
1497 case 3: vertexHLSL += "w"; break;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001498 }
1499 }
1500 }
1501 }
1502
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001503 vertexHLSL += " = " + varying->name;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001504
1505 if (varying->array)
1506 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001507 vertexHLSL += "[" + str(i) + "]";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001508 }
1509
1510 if (rows > 1)
1511 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001512 vertexHLSL += "[" + str(j) + "]";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001513 }
1514
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001515 vertexHLSL += ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001516 }
1517 }
1518 }
1519 }
1520
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001521 vertexHLSL += "\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001522 " return output;\n"
1523 "}\n";
1524
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001525 pixelHLSL += "struct PS_INPUT\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001526 "{\n";
1527
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001528 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001529 {
1530 if (varying->reg >= 0)
1531 {
1532 for (int i = 0; i < varying->size; i++)
1533 {
1534 int rows = VariableRowCount(varying->type);
1535 for (int j = 0; j < rows; j++)
1536 {
1537 std::string n = str(varying->reg + i * rows + j);
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001538 pixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001539 }
1540 }
1541 }
1542 else UNREACHABLE();
1543 }
1544
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001545 if (fragmentShader->mUsesFragCoord)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001546 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001547 pixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001548 if (sm3) {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001549 pixelHLSL += " float2 dx_VPos : VPOS;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001550 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001551 }
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001552
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001553 if (fragmentShader->mUsesPointCoord && sm3)
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001554 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001555 pixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001556 }
1557
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001558 if (fragmentShader->mUsesFrontFacing)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001559 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001560 pixelHLSL += " float vFace : VFACE;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001561 }
1562
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001563 pixelHLSL += "};\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001564 "\n"
1565 "struct PS_OUTPUT\n"
1566 "{\n"
1567 " float4 gl_Color[1] : COLOR;\n"
1568 "};\n"
1569 "\n"
1570 "PS_OUTPUT main(PS_INPUT input)\n"
1571 "{\n";
1572
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001573 if (fragmentShader->mUsesFragCoord)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001574 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001575 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00001576
1577 if (sm3)
1578 {
1579 // dx_Coord.y contains the render target height. See Context::applyRenderTarget()
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001580 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00001581 " gl_FragCoord.y = dx_Coord.y - input.dx_VPos.y - 0.5;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001582 }
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00001583 else
1584 {
1585 // dx_Coord contains the viewport width/2, height/2, center.x and center.y. See Context::applyRenderTarget()
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001586 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Coord.x + dx_Coord.z;\n"
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00001587 " gl_FragCoord.y = -(input.gl_FragCoord.y * rhw) * dx_Coord.y + dx_Coord.w;\n";
1588 }
1589
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001590 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001591 " gl_FragCoord.w = rhw;\n";
1592 }
1593
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001594 if (fragmentShader->mUsesPointCoord && sm3)
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001595 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001596 pixelHLSL += " gl_PointCoord = input.gl_PointCoord;\n";
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001597 }
1598
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001599 if (fragmentShader->mUsesFrontFacing)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001600 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001601 pixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001602 }
1603
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001604 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001605 {
1606 if (varying->reg >= 0)
1607 {
1608 for (int i = 0; i < varying->size; i++)
1609 {
1610 int rows = VariableRowCount(varying->type);
1611 for (int j = 0; j < rows; j++)
1612 {
1613 std::string n = str(varying->reg + i * rows + j);
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001614 pixelHLSL += " " + varying->name;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001615
1616 if (varying->array)
1617 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001618 pixelHLSL += "[" + str(i) + "]";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001619 }
1620
1621 if (rows > 1)
1622 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001623 pixelHLSL += "[" + str(j) + "]";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001624 }
1625
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001626 pixelHLSL += " = input.v" + n + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001627 }
1628 }
1629 }
1630 else UNREACHABLE();
1631 }
1632
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001633 pixelHLSL += "\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001634 " gl_main();\n"
1635 "\n"
1636 " PS_OUTPUT output;\n"
1637 " output.gl_Color[0] = gl_Color[0];\n"
1638 "\n"
1639 " return output;\n"
1640 "}\n";
1641
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001642 return true;
1643}
1644
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001645// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1646// compiling them into binaries, determining the attribute mappings, and collecting
1647// a list of uniforms
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001648void Program::link()
1649{
1650 link(mAttributeBindings, mFragmentShader, mVertexShader);
1651}
1652
1653void Program::link(const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001654{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001655 unlink();
1656
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001657 if (!fragmentShader || !fragmentShader->isCompiled())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001658 {
1659 return;
1660 }
1661
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001662 if (!vertexShader || !vertexShader->isCompiled())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001663 {
1664 return;
1665 }
1666
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001667 std::string pixelHLSL = fragmentShader->getHLSL();
1668 std::string vertexHLSL = vertexShader->getHLSL();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001669
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001670 if (!linkVaryings(pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001671 {
1672 return;
1673 }
1674
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001675 Context *context = getContext();
1676 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1677 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1678
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001679 ID3D10Blob *vertexBinary = compileToBinary(vertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1680 ID3D10Blob *pixelBinary = compileToBinary(pixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001681
1682 if (vertexBinary && pixelBinary)
1683 {
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +00001684 HRESULT vertexResult = mDevice->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1685 HRESULT pixelResult = mDevice->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001686
1687 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1688 {
1689 return error(GL_OUT_OF_MEMORY);
1690 }
1691
1692 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001693
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001694 vertexBinary->Release();
1695 pixelBinary->Release();
1696 vertexBinary = NULL;
1697 pixelBinary = NULL;
1698
1699 if (mVertexExecutable && mPixelExecutable)
1700 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001701 if (!linkAttributes(attributeBindings, fragmentShader, vertexShader))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001702 {
1703 return;
1704 }
1705
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001706 if (!linkUniforms(GL_FRAGMENT_SHADER, mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001707 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001708 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001709 }
1710
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001711 if (!linkUniforms(GL_VERTEX_SHADER, mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001712 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001713 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001714 }
1715
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001716 // these uniforms are searched as already-decorated because gl_ and dx_
1717 // are reserved prefixes, and do not receive additional decoration
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001718 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
1719 mDxDepthLocation = getUniformLocation("dx_Depth");
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00001720 mDxCoordLocation = getUniformLocation("dx_Coord");
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001721 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
1722 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
1723 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00001724
daniel@transgaming.com11399d52012-04-28 00:35:14 +00001725 context->markDxUniformsDirty();
1726
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001727 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001728 }
1729 }
1730}
1731
1732// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001733bool Program::linkAttributes(const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001734{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001735 unsigned int usedLocations = 0;
1736
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001737 // Link attributes that have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001738 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001739 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001740 int location = attributeBindings.getAttributeBinding(attribute->name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001741
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001742 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001743 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001744 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001745 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001746 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001747 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001748
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001749 mLinkedAttribute[location] = *attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001750
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001751 int rows = VariableRowCount(attribute->type);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001752
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001753 if (rows + location > MAX_VERTEX_ATTRIBS)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001754 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001755 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 +00001756
1757 return false;
1758 }
1759
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001760 for (int i = 0; i < rows; i++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001761 {
1762 usedLocations |= 1 << (location + i);
1763 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001764 }
1765 }
1766
1767 // Link attributes that don't have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001768 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001769 {
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001770 int location = attributeBindings.getAttributeBinding(attribute->name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001771
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001772 if (location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001773 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001774 int rows = VariableRowCount(attribute->type);
1775 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001776
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001777 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001778 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001779 appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001780
1781 return false; // Fail to link
1782 }
1783
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001784 mLinkedAttribute[availableIndex] = *attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001785 }
1786 }
1787
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001788 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001789 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001790 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001791 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001792
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001793 for (int r = 0; r < rows; r++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001794 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001795 mSemanticIndex[attributeIndex++] = index++;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001796 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001797 }
1798
1799 return true;
1800}
1801
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001802int AttributeBindings::getAttributeBinding(const std::string &name) const
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001803{
1804 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1805 {
1806 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1807 {
1808 return location;
1809 }
1810 }
1811
1812 return -1;
1813}
1814
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001815bool Program::linkUniforms(GLenum shader, ID3DXConstantTable *constantTable)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001816{
1817 D3DXCONSTANTTABLE_DESC constantTableDescription;
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001818
1819 constantTable->GetDesc(&constantTableDescription);
1820
1821 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1822 {
1823 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001824
1825 D3DXCONSTANT_DESC constantDescription;
1826 UINT descriptionCount = 1;
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001827 HRESULT result = constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1828 ASSERT(SUCCEEDED(result));
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001829
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001830 if (!defineUniform(shader, constantHandle, constantDescription))
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001831 {
1832 return false;
1833 }
1834 }
1835
1836 return true;
1837}
1838
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001839// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001840// Returns true if succesful (uniform not already defined)
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001841bool Program::defineUniform(GLenum shader, const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001842{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001843 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1844 {
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001845 for (unsigned int i = 0; i < constantDescription.RegisterCount; i++)
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001846 {
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001847 D3DXHANDLE psConstant = mConstantTablePS->GetConstantByName(NULL, constantDescription.Name);
1848 D3DXHANDLE vsConstant = mConstantTableVS->GetConstantByName(NULL, constantDescription.Name);
1849
1850 if (psConstant)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001851 {
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001852 unsigned int samplerIndex = mConstantTablePS->GetSamplerIndex(psConstant) + i;
1853
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001854 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1855 {
1856 mSamplersPS[samplerIndex].active = true;
1857 mSamplersPS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1858 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00001859 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001860 }
1861 else
1862 {
1863 appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
1864 return false;
1865 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001866 }
1867
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001868 if (vsConstant)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001869 {
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001870 unsigned int samplerIndex = mConstantTableVS->GetSamplerIndex(vsConstant) + i;
1871
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001872 if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
1873 {
1874 mSamplersVS[samplerIndex].active = true;
1875 mSamplersVS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1876 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00001877 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001878 }
1879 else
1880 {
1881 appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
1882 return false;
1883 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001884 }
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001885 }
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001886 }
1887
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001888 switch(constantDescription.Class)
1889 {
1890 case D3DXPC_STRUCT:
1891 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001892 for (unsigned int arrayIndex = 0; arrayIndex < constantDescription.Elements; arrayIndex++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001893 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001894 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001895 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001896 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1897
1898 D3DXCONSTANT_DESC fieldDescription;
1899 UINT descriptionCount = 1;
1900
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001901 HRESULT result = mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1902 ASSERT(SUCCEEDED(result));
daniel@transgaming.comce864422010-11-18 13:16:49 +00001903
1904 std::string structIndex = (constantDescription.Elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
1905
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001906 if (!defineUniform(shader, fieldHandle, fieldDescription, name + constantDescription.Name + structIndex + "."))
daniel@transgaming.comce864422010-11-18 13:16:49 +00001907 {
1908 return false;
1909 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001910 }
1911 }
1912
1913 return true;
1914 }
1915 case D3DXPC_SCALAR:
1916 case D3DXPC_VECTOR:
1917 case D3DXPC_MATRIX_COLUMNS:
1918 case D3DXPC_OBJECT:
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001919 return defineUniform(shader, constantDescription, name + constantDescription.Name);
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001920 default:
1921 UNREACHABLE();
1922 return false;
1923 }
1924}
1925
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001926bool Program::defineUniform(GLenum shader, const D3DXCONSTANT_DESC &constantDescription, const std::string &_name)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001927{
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001928 Uniform *uniform = createUniform(constantDescription, _name);
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001929
1930 if(!uniform)
1931 {
1932 return false;
1933 }
1934
1935 // Check if already defined
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001936 GLint location = getUniformLocation(uniform->name);
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001937 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001938
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001939 if (location >= 0)
1940 {
1941 delete uniform;
daniel@transgaming.comec909fc2012-06-05 19:51:49 +00001942 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001943 }
1944
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001945 if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constantDescription);
1946 if (shader == GL_VERTEX_SHADER) uniform->vs.set(constantDescription);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00001947
daniel@transgaming.comec909fc2012-06-05 19:51:49 +00001948 if (location >= 0)
1949 {
1950 return uniform->type == type;
1951 }
1952
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001953 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001954 unsigned int uniformIndex = mUniforms.size() - 1;
1955
1956 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1957 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001958 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001959 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001960
1961 return true;
1962}
1963
apatrick@chromium.orge057c5d2012-01-26 19:18:24 +00001964Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, const std::string &_name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001965{
1966 if (constantDescription.Rows == 1) // Vectors and scalars
1967 {
1968 switch (constantDescription.Type)
1969 {
1970 case D3DXPT_SAMPLER2D:
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001971 switch (constantDescription.Columns)
1972 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001973 case 1: return new Uniform(GL_SAMPLER_2D, _name, constantDescription.Elements);
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001974 default: UNREACHABLE();
1975 }
1976 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001977 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001978 switch (constantDescription.Columns)
1979 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001980 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001981 default: UNREACHABLE();
1982 }
1983 break;
1984 case D3DXPT_BOOL:
1985 switch (constantDescription.Columns)
1986 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001987 case 1: return new Uniform(GL_BOOL, _name, constantDescription.Elements);
1988 case 2: return new Uniform(GL_BOOL_VEC2, _name, constantDescription.Elements);
1989 case 3: return new Uniform(GL_BOOL_VEC3, _name, constantDescription.Elements);
1990 case 4: return new Uniform(GL_BOOL_VEC4, _name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001991 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001992 }
1993 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001994 case D3DXPT_INT:
1995 switch (constantDescription.Columns)
1996 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001997 case 1: return new Uniform(GL_INT, _name, constantDescription.Elements);
1998 case 2: return new Uniform(GL_INT_VEC2, _name, constantDescription.Elements);
1999 case 3: return new Uniform(GL_INT_VEC3, _name, constantDescription.Elements);
2000 case 4: return new Uniform(GL_INT_VEC4, _name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002001 default: UNREACHABLE();
2002 }
2003 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002004 case D3DXPT_FLOAT:
2005 switch (constantDescription.Columns)
2006 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002007 case 1: return new Uniform(GL_FLOAT, _name, constantDescription.Elements);
2008 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constantDescription.Elements);
2009 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constantDescription.Elements);
2010 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002011 default: UNREACHABLE();
2012 }
2013 break;
2014 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002015 UNREACHABLE();
2016 }
2017 }
2018 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
2019 {
2020 switch (constantDescription.Type)
2021 {
2022 case D3DXPT_FLOAT:
2023 switch (constantDescription.Rows)
2024 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002025 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constantDescription.Elements);
2026 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constantDescription.Elements);
2027 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002028 default: UNREACHABLE();
2029 }
2030 break;
2031 default: UNREACHABLE();
2032 }
2033 }
2034 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00002035
2036 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002037}
2038
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002039// This method needs to match OutputHLSL::decorate
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002040std::string Program::decorateAttribute(const std::string &name)
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002041{
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002042 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002043 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002044 return "_" + name;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002045 }
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002046
2047 return name;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002048}
2049
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002050std::string Program::undecorateUniform(const std::string &_name)
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002051{
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002052 std::string name = _name;
2053
2054 // Remove any structure field decoration
2055 size_t pos = 0;
2056 while ((pos = name.find("._", pos)) != std::string::npos)
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002057 {
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002058 name.replace(pos, 2, ".");
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002059 }
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002060
2061 // Remove the leading decoration
2062 if (name[0] == '_')
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002063 {
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002064 return name.substr(1);
2065 }
2066 else if (name.compare(0, 3, "ar_") == 0)
2067 {
2068 return name.substr(3);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002069 }
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002070
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002071 return name;
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002072}
2073
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002074void Program::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002075{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002076 float vector[D3D9_MAX_FLOAT_CONSTANTS * 4];
2077 BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS];
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002078
daniel@transgaming.com28be96b2012-06-05 19:51:46 +00002079 if (targetUniform->ps.float4Index >= 0 || targetUniform->vs.float4Index >= 0)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002080 {
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002081 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002082 for (int i = 0; i < count; i++)
2083 {
2084 for (int j = 0; j < 4; j++)
2085 {
2086 if (j < width)
2087 {
2088 vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f;
2089 }
2090 else
2091 {
2092 vector[i * 4 + j] = 0.0f;
2093 }
2094 }
2095 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002096 }
2097
daniel@transgaming.com28be96b2012-06-05 19:51:46 +00002098 if (targetUniform->ps.boolIndex >= 0 || targetUniform->vs.boolIndex >= 0)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002099 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002100 int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0;
2101 int vsCount = targetUniform->vs.boolIndex >= 0 ? targetUniform->vs.registerCount : 0;
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002102 int copyCount = std::min(count * width, std::max(psCount, vsCount));
2103 ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS);
2104 for (int i = 0; i < copyCount; i++)
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002105 {
2106 boolVector[i] = v[i] != GL_FALSE;
2107 }
2108 }
2109
daniel@transgaming.com28be96b2012-06-05 19:51:46 +00002110 if (targetUniform->ps.float4Index >= 0)
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002111 {
daniel@transgaming.com28be96b2012-06-05 19:51:46 +00002112 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002113 }
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002114
daniel@transgaming.com28be96b2012-06-05 19:51:46 +00002115 if (targetUniform->ps.boolIndex >= 0)
2116 {
2117 mDevice->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount);
2118 }
2119
2120 if (targetUniform->vs.float4Index >= 0)
2121 {
2122 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount);
2123 }
2124
2125 if (targetUniform->vs.boolIndex >= 0)
2126 {
2127 mDevice->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002128 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002129}
2130
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002131bool Program::applyUniformnfv(Uniform *targetUniform, const GLfloat *v)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002132{
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002133 if (targetUniform->ps.registerCount)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002134 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002135 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002136 }
2137
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002138 if (targetUniform->vs.registerCount)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002139 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002140 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002141 }
2142
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002143 return true;
2144}
2145
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002146bool Program::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002147{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002148 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2149 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002150
2151 for (int i = 0; i < count; i++)
2152 {
2153 vector[i] = D3DXVECTOR4((float)v[i], 0, 0, 0);
2154 }
2155
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002156 if (targetUniform->ps.registerCount)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002157 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002158 if (targetUniform->ps.samplerIndex >= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002159 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002160 unsigned int firstIndex = targetUniform->ps.samplerIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002161
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002162 for (int i = 0; i < count; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002163 {
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002164 unsigned int samplerIndex = firstIndex + i;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002165
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002166 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002167 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002168 ASSERT(mSamplersPS[samplerIndex].active);
2169 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002170 }
2171 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002172 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002173 else
2174 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002175 ASSERT(targetUniform->ps.float4Index >= 0);
2176 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount);
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002177 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002178 }
2179
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002180 if (targetUniform->vs.registerCount)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002181 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002182 if (targetUniform->vs.samplerIndex >= 0)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002183 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002184 unsigned int firstIndex = targetUniform->vs.samplerIndex;
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002185
2186 for (int i = 0; i < count; i++)
2187 {
2188 unsigned int samplerIndex = firstIndex + i;
2189
2190 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2191 {
2192 ASSERT(mSamplersVS[samplerIndex].active);
2193 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2194 }
2195 }
2196 }
2197 else
2198 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002199 ASSERT(targetUniform->vs.float4Index >= 0);
2200 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002201 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002202 }
2203
2204 return true;
2205}
2206
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002207bool Program::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002208{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002209 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2210 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002211
2212 for (int i = 0; i < count; i++)
2213 {
2214 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2215
2216 v += 2;
2217 }
2218
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002219 applyUniformniv(targetUniform, count, vector);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002220
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002221 return true;
2222}
2223
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002224bool Program::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002225{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002226 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2227 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002228
2229 for (int i = 0; i < count; i++)
2230 {
2231 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2232
2233 v += 3;
2234 }
2235
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002236 applyUniformniv(targetUniform, count, vector);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002237
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002238 return true;
2239}
2240
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002241bool Program::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002242{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002243 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2244 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002245
2246 for (int i = 0; i < count; i++)
2247 {
2248 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2249
2250 v += 4;
2251 }
2252
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002253 applyUniformniv(targetUniform, count, vector);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002254
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002255 return true;
2256}
2257
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002258void Program::applyUniformniv(Uniform *targetUniform, GLsizei count, const D3DXVECTOR4 *vector)
2259{
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002260 if (targetUniform->ps.registerCount)
2261 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002262 ASSERT(targetUniform->ps.float4Index >= 0);
2263 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002264 }
2265
2266 if (targetUniform->vs.registerCount)
2267 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002268 ASSERT(targetUniform->vs.float4Index >= 0);
2269 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002270 }
2271}
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002272
2273// append a santized message to the program info log.
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002274// The D3D compiler includes a fake file path in some of the warning or error
2275// messages, so lets remove all occurrences of this fake file path from the log.
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002276void Program::appendToInfoLogSanitized(const char *message)
2277{
2278 std::string msg(message);
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002279
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002280 size_t found;
2281 do
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002282 {
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002283 found = msg.find(fakepath);
2284 if (found != std::string::npos)
2285 {
2286 msg.erase(found, strlen(fakepath));
2287 }
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002288 }
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002289 while (found != std::string::npos);
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002290
2291 appendToInfoLog("%s\n", msg.c_str());
2292}
2293
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002294void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002295{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002296 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002297 {
2298 return;
2299 }
2300
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002301 char info[1024];
2302
2303 va_list vararg;
2304 va_start(vararg, format);
2305 vsnprintf(info, sizeof(info), format, vararg);
2306 va_end(vararg);
2307
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002308 size_t infoLength = strlen(info);
2309
2310 if (!mInfoLog)
2311 {
2312 mInfoLog = new char[infoLength + 1];
2313 strcpy(mInfoLog, info);
2314 }
2315 else
2316 {
2317 size_t logLength = strlen(mInfoLog);
2318 char *newLog = new char[logLength + infoLength + 1];
2319 strcpy(newLog, mInfoLog);
2320 strcpy(newLog + logLength, info);
2321
2322 delete[] mInfoLog;
2323 mInfoLog = newLog;
2324 }
2325}
2326
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002327void Program::resetInfoLog()
2328{
2329 if (mInfoLog)
2330 {
2331 delete [] mInfoLog;
daniel@transgaming.com6a20d102010-08-31 13:54:27 +00002332 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002333 }
2334}
2335
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +00002336// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002337void Program::unlink(bool destroy)
2338{
2339 if (destroy) // Object being destructed
2340 {
2341 if (mFragmentShader)
2342 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002343 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002344 mFragmentShader = NULL;
2345 }
2346
2347 if (mVertexShader)
2348 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002349 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002350 mVertexShader = NULL;
2351 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002352 }
2353
2354 if (mPixelExecutable)
2355 {
2356 mPixelExecutable->Release();
2357 mPixelExecutable = NULL;
2358 }
2359
2360 if (mVertexExecutable)
2361 {
2362 mVertexExecutable->Release();
2363 mVertexExecutable = NULL;
2364 }
2365
2366 if (mConstantTablePS)
2367 {
2368 mConstantTablePS->Release();
2369 mConstantTablePS = NULL;
2370 }
2371
2372 if (mConstantTableVS)
2373 {
2374 mConstantTableVS->Release();
2375 mConstantTableVS = NULL;
2376 }
2377
2378 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2379 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002380 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002381 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002382 }
2383
2384 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2385 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002386 mSamplersPS[index].active = false;
2387 }
2388
2389 for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
2390 {
2391 mSamplersVS[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002392 }
2393
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00002394 mUsedVertexSamplerRange = 0;
2395 mUsedPixelSamplerRange = 0;
2396
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002397 while (!mUniforms.empty())
2398 {
2399 delete mUniforms.back();
2400 mUniforms.pop_back();
2401 }
2402
daniel@transgaming.com31754962010-11-28 02:02:52 +00002403 mDxDepthRangeLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002404 mDxDepthLocation = -1;
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00002405 mDxCoordLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002406 mDxHalfPixelSizeLocation = -1;
2407 mDxFrontCCWLocation = -1;
2408 mDxPointsOrLinesLocation = -1;
2409
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002410 mUniformIndex.clear();
2411
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002412 delete[] mInfoLog;
2413 mInfoLog = NULL;
2414
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002415 mLinked = false;
2416}
2417
2418bool Program::isLinked()
2419{
2420 return mLinked;
2421}
2422
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002423bool Program::isValidated() const
2424{
2425 return mValidated;
2426}
2427
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002428void Program::release()
2429{
2430 mRefCount--;
2431
2432 if (mRefCount == 0 && mDeleteStatus)
2433 {
2434 mResourceManager->deleteProgram(mHandle);
2435 }
2436}
2437
2438void Program::addRef()
2439{
2440 mRefCount++;
2441}
2442
2443unsigned int Program::getRefCount() const
2444{
2445 return mRefCount;
2446}
2447
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002448unsigned int Program::getSerial() const
2449{
2450 return mSerial;
2451}
2452
2453unsigned int Program::issueSerial()
2454{
2455 return mCurrentSerial++;
2456}
2457
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002458int Program::getInfoLogLength() const
2459{
2460 if (!mInfoLog)
2461 {
2462 return 0;
2463 }
2464 else
2465 {
2466 return strlen(mInfoLog) + 1;
2467 }
2468}
2469
2470void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2471{
2472 int index = 0;
2473
daniel@transgaming.com807d8c32012-04-04 15:06:04 +00002474 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002475 {
daniel@transgaming.com807d8c32012-04-04 15:06:04 +00002476 if (mInfoLog)
2477 {
2478 index = std::min(bufSize - 1, (int)strlen(mInfoLog));
2479 memcpy(infoLog, mInfoLog, index);
2480 }
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002481
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002482 infoLog[index] = '\0';
2483 }
2484
2485 if (length)
2486 {
2487 *length = index;
2488 }
2489}
2490
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002491void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2492{
2493 int total = 0;
2494
2495 if (mVertexShader)
2496 {
2497 if (total < maxCount)
2498 {
2499 shaders[total] = mVertexShader->getHandle();
2500 }
2501
2502 total++;
2503 }
2504
2505 if (mFragmentShader)
2506 {
2507 if (total < maxCount)
2508 {
2509 shaders[total] = mFragmentShader->getHandle();
2510 }
2511
2512 total++;
2513 }
2514
2515 if (count)
2516 {
2517 *count = total;
2518 }
2519}
2520
daniel@transgaming.com85423182010-04-22 13:35:27 +00002521void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2522{
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002523 // Skip over inactive attributes
2524 unsigned int activeAttribute = 0;
2525 unsigned int attribute;
2526 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
daniel@transgaming.com85423182010-04-22 13:35:27 +00002527 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002528 if (mLinkedAttribute[attribute].name.empty())
daniel@transgaming.com85423182010-04-22 13:35:27 +00002529 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002530 continue;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002531 }
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002532
2533 if (activeAttribute == index)
2534 {
2535 break;
2536 }
2537
2538 activeAttribute++;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002539 }
2540
2541 if (bufsize > 0)
2542 {
2543 const char *string = mLinkedAttribute[attribute].name.c_str();
2544
2545 strncpy(name, string, bufsize);
2546 name[bufsize - 1] = '\0';
2547
2548 if (length)
2549 {
2550 *length = strlen(name);
2551 }
2552 }
2553
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002554 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002555
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002556 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002557}
2558
2559GLint Program::getActiveAttributeCount()
2560{
2561 int count = 0;
2562
2563 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2564 {
2565 if (!mLinkedAttribute[attributeIndex].name.empty())
2566 {
2567 count++;
2568 }
2569 }
2570
2571 return count;
2572}
2573
2574GLint Program::getActiveAttributeMaxLength()
2575{
2576 int maxLength = 0;
2577
2578 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2579 {
2580 if (!mLinkedAttribute[attributeIndex].name.empty())
2581 {
2582 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2583 }
2584 }
2585
2586 return maxLength;
2587}
2588
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002589void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2590{
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002591 // Skip over internal uniforms
2592 unsigned int activeUniform = 0;
2593 unsigned int uniform;
2594 for (uniform = 0; uniform < mUniforms.size(); uniform++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002595 {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002596 if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002597 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002598 continue;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002599 }
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002600
2601 if (activeUniform == index)
2602 {
2603 break;
2604 }
2605
2606 activeUniform++;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002607 }
2608
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002609 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2610
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002611 if (bufsize > 0)
2612 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002613 std::string string = mUniforms[uniform]->name;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002614
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002615 if (mUniforms[uniform]->isArray())
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002616 {
2617 string += "[0]";
2618 }
2619
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002620 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002621 name[bufsize - 1] = '\0';
2622
2623 if (length)
2624 {
2625 *length = strlen(name);
2626 }
2627 }
2628
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002629 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002630
2631 *type = mUniforms[uniform]->type;
2632}
2633
2634GLint Program::getActiveUniformCount()
2635{
2636 int count = 0;
2637
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002638 unsigned int numUniforms = mUniforms.size();
2639 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002640 {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002641 if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002642 {
2643 count++;
2644 }
2645 }
2646
2647 return count;
2648}
2649
2650GLint Program::getActiveUniformMaxLength()
2651{
2652 int maxLength = 0;
2653
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002654 unsigned int numUniforms = mUniforms.size();
2655 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002656 {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002657 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002658 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002659 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2660 if (mUniforms[uniformIndex]->isArray())
zmo@google.com53d73e02011-03-24 21:27:57 +00002661 {
2662 length += 3; // Counting in "[0]".
2663 }
2664 maxLength = std::max(length, maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002665 }
2666 }
2667
2668 return maxLength;
2669}
2670
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002671void Program::flagForDeletion()
2672{
2673 mDeleteStatus = true;
2674}
2675
2676bool Program::isFlaggedForDeletion() const
2677{
2678 return mDeleteStatus;
2679}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002680
2681void Program::validate()
2682{
2683 resetInfoLog();
2684
2685 if (!isLinked())
2686 {
2687 appendToInfoLog("Program has not been successfully linked.");
2688 mValidated = false;
2689 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002690 else
2691 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002692 applyUniforms();
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002693 if (!validateSamplers(true))
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002694 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002695 mValidated = false;
2696 }
2697 else
2698 {
2699 mValidated = true;
2700 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002701 }
2702}
2703
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002704bool Program::validateSamplers(bool logErrors)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002705{
2706 // if any two active samplers in a program are of different types, but refer to the same
2707 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2708 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002709
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002710 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002711 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2712
2713 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2714 {
2715 textureUnitType[i] = TEXTURE_UNKNOWN;
2716 }
2717
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00002718 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002719 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002720 if (mSamplersPS[i].active)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002721 {
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002722 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002723
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002724 if (unit >= maxCombinedTextureImageUnits)
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002725 {
2726 if (logErrors)
2727 {
2728 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
2729 }
2730
2731 return false;
2732 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002733
2734 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002735 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002736 if (mSamplersPS[i].textureType != textureUnitType[unit])
2737 {
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002738 if (logErrors)
2739 {
2740 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2741 }
2742
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002743 return false;
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002744 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002745 }
2746 else
2747 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002748 textureUnitType[unit] = mSamplersPS[i].textureType;
2749 }
2750 }
2751 }
2752
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00002753 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002754 {
2755 if (mSamplersVS[i].active)
2756 {
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002757 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002758
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002759 if (unit >= maxCombinedTextureImageUnits)
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002760 {
2761 if (logErrors)
2762 {
2763 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
2764 }
2765
2766 return false;
2767 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002768
2769 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2770 {
2771 if (mSamplersVS[i].textureType != textureUnitType[unit])
2772 {
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002773 if (logErrors)
2774 {
2775 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2776 }
2777
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002778 return false;
2779 }
2780 }
2781 else
2782 {
2783 textureUnitType[unit] = mSamplersVS[i].textureType;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002784 }
2785 }
2786 }
2787
2788 return true;
2789}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002790
daniel@transgaming.com31754962010-11-28 02:02:52 +00002791GLint Program::getDxDepthRangeLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002792{
daniel@transgaming.com31754962010-11-28 02:02:52 +00002793 return mDxDepthRangeLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002794}
2795
2796GLint Program::getDxDepthLocation() const
2797{
2798 return mDxDepthLocation;
2799}
2800
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00002801GLint Program::getDxCoordLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002802{
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00002803 return mDxCoordLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002804}
2805
2806GLint Program::getDxHalfPixelSizeLocation() const
2807{
2808 return mDxHalfPixelSizeLocation;
2809}
2810
2811GLint Program::getDxFrontCCWLocation() const
2812{
2813 return mDxFrontCCWLocation;
2814}
2815
2816GLint Program::getDxPointsOrLinesLocation() const
2817{
2818 return mDxPointsOrLinesLocation;
2819}
2820
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002821}