blob: beb0fae8af49303e26dd35231c812dae23f03aea [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
daniel@transgaming.com024f1a92011-09-20 16:06:25 +000036Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize)
daniel@transgaming.comc72c6412011-09-20 16:09:17 +000037 : type(type), _name(_name), name(Program::undecorateUniform(_name)), arraySize(arraySize)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000038{
daniel@transgaming.come918ea22011-11-12 03:15:28 +000039 int bytes = UniformInternalSize(type) * arraySize;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000040 data = new unsigned char[bytes];
41 memset(data, 0, bytes);
42 dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000043}
44
45Uniform::~Uniform()
46{
47 delete[] data;
48}
49
daniel@transgaming.com024f1a92011-09-20 16:06:25 +000050bool Uniform::isArray()
51{
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +000052 return _name.compare(0, 3, "ar_") == 0;
daniel@transgaming.com024f1a92011-09-20 16:06:25 +000053}
54
55UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index)
daniel@transgaming.comc72c6412011-09-20 16:09:17 +000056 : name(Program::undecorateUniform(_name)), element(element), index(index)
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +000057{
58}
59
daniel@transgaming.com73a5db62010-10-15 17:58:13 +000060Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000061{
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +000062 mDevice = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000063 mFragmentShader = NULL;
64 mVertexShader = NULL;
65
66 mPixelExecutable = NULL;
67 mVertexExecutable = NULL;
68 mConstantTablePS = NULL;
69 mConstantTableVS = NULL;
70
daniel@transgaming.comcba50572010-03-28 19:36:09 +000071 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +000072 mValidated = false;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000073
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000074 unlink();
75
76 mDeleteStatus = false;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000077
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000078 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000079}
80
81Program::~Program()
82{
83 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000084
85 if (mVertexShader != NULL)
86 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000087 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000088 }
89
90 if (mFragmentShader != NULL)
91 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000092 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000093 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000094}
95
96bool Program::attachShader(Shader *shader)
97{
98 if (shader->getType() == GL_VERTEX_SHADER)
99 {
100 if (mVertexShader)
101 {
102 return false;
103 }
104
105 mVertexShader = (VertexShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000106 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000107 }
108 else if (shader->getType() == GL_FRAGMENT_SHADER)
109 {
110 if (mFragmentShader)
111 {
112 return false;
113 }
114
115 mFragmentShader = (FragmentShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000116 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000117 }
118 else UNREACHABLE();
119
120 return true;
121}
122
123bool Program::detachShader(Shader *shader)
124{
125 if (shader->getType() == GL_VERTEX_SHADER)
126 {
127 if (mVertexShader != shader)
128 {
129 return false;
130 }
131
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000132 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000133 mVertexShader = NULL;
134 }
135 else if (shader->getType() == GL_FRAGMENT_SHADER)
136 {
137 if (mFragmentShader != shader)
138 {
139 return false;
140 }
141
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000142 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143 mFragmentShader = NULL;
144 }
145 else UNREACHABLE();
146
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000147 return true;
148}
149
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000150int Program::getAttachedShadersCount() const
151{
152 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
153}
154
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000155IDirect3DPixelShader9 *Program::getPixelShader()
156{
157 return mPixelExecutable;
158}
159
160IDirect3DVertexShader9 *Program::getVertexShader()
161{
162 return mVertexExecutable;
163}
164
165void Program::bindAttributeLocation(GLuint index, const char *name)
166{
167 if (index < MAX_VERTEX_ATTRIBS)
168 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000169 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
170 {
171 mAttributeBinding[i].erase(name);
172 }
173
174 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000175 }
176}
177
178GLuint Program::getAttributeLocation(const char *name)
179{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000180 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000181 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000182 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000183 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000184 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000185 {
186 return index;
187 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000188 }
189 }
190
191 return -1;
192}
193
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000194int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000195{
daniel@transgaming.com733ba932011-04-14 15:03:48 +0000196 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
197
198 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000199}
200
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +0000201// Returns one more than the highest sampler index used.
202GLint Program::getUsedSamplerRange(SamplerType type)
203{
204 switch (type)
205 {
206 case SAMPLER_PIXEL:
207 return mUsedPixelSamplerRange;
208 case SAMPLER_VERTEX:
209 return mUsedVertexSamplerRange;
210 default:
211 UNREACHABLE();
212 return 0;
213 }
214}
215
daniel@transgaming.com9ba680a2011-05-11 15:37:11 +0000216// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
217// index (0-15 for the pixel shader and 0-3 for the vertex shader).
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000218GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000219{
jbauman@chromium.org8b3c1af2011-10-12 01:21:41 +0000220 GLint logicalTextureUnit = -1;
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000221
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000222 switch (type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000224 case SAMPLER_PIXEL:
225 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
226
227 if (mSamplersPS[samplerIndex].active)
228 {
229 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
230 }
231 break;
232 case SAMPLER_VERTEX:
233 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
234
235 if (mSamplersVS[samplerIndex].active)
236 {
237 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
238 }
239 break;
240 default: UNREACHABLE();
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000241 }
242
jbauman@chromium.org8b3c1af2011-10-12 01:21:41 +0000243 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)getContext()->getMaximumCombinedTextureImageUnits())
daniel@transgaming.com4071e662010-05-12 16:51:16 +0000244 {
245 return logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000246 }
247
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000248 return -1;
249}
250
daniel@transgaming.com9ba680a2011-05-11 15:37:11 +0000251// Returns the texture type for a given Direct3D 9 sampler type and
252// index (0-15 for the pixel shader and 0-3 for the vertex shader).
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000253TextureType Program::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000254{
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000255 switch (type)
256 {
257 case SAMPLER_PIXEL:
258 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
259 ASSERT(mSamplersPS[samplerIndex].active);
260 return mSamplersPS[samplerIndex].textureType;
261 case SAMPLER_VERTEX:
262 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
263 ASSERT(mSamplersVS[samplerIndex].active);
264 return mSamplersVS[samplerIndex].textureType;
265 default: UNREACHABLE();
266 }
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000267
daniel@transgaming.comd4a35172011-05-11 15:36:45 +0000268 return TEXTURE_2D;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000269}
270
daniel@transgaming.com024f1a92011-09-20 16:06:25 +0000271GLint Program::getUniformLocation(std::string name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000272{
apatrick@chromium.orga1d80592012-01-25 21:52:10 +0000273 unsigned int subscript = 0;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000274
daniel@transgaming.comce864422010-11-18 13:16:49 +0000275 // Strip any trailing array operator and retrieve the subscript
daniel@transgaming.com024f1a92011-09-20 16:06:25 +0000276 size_t open = name.find_last_of('[');
277 size_t close = name.find_last_of(']');
278 if (open != std::string::npos && close == name.length() - 1)
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000279 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +0000280 subscript = atoi(name.substr(open + 1).c_str());
281 name.erase(open);
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +0000282 }
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000283
daniel@transgaming.comd08ea902010-05-14 19:41:36 +0000284 unsigned int numUniforms = mUniformIndex.size();
285 for (unsigned int location = 0; location < numUniforms; location++)
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000286 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +0000287 if (mUniformIndex[location].name == name &&
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000288 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000289 {
290 return location;
291 }
292 }
293
294 return -1;
295}
296
297bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
298{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000299 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000300 {
301 return false;
302 }
303
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000304 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000305 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000306
307 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000308 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000309 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000310
311 if (arraySize == 1 && count > 1)
312 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
313
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000314 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000315
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000316 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
317
318 for (int i = 0; i < count; i++)
319 {
320 target[0] = v[0];
321 target[1] = 0;
322 target[2] = 0;
323 target[3] = 0;
324 target += 4;
325 v += 1;
326 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000327 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000328 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000329 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000330 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000331
332 if (arraySize == 1 && count > 1)
333 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000334
335 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000336 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000337
338 for (int i = 0; i < count; ++i)
339 {
340 if (v[i] == 0.0f)
341 {
342 boolParams[i] = GL_FALSE;
343 }
344 else
345 {
346 boolParams[i] = GL_TRUE;
347 }
348 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000349 }
350 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000351 {
352 return false;
353 }
354
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000355 return true;
356}
357
358bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
359{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000360 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000361 {
362 return false;
363 }
364
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000365 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000366 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000367
368 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000369 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000370 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000371
372 if (arraySize == 1 && count > 1)
373 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
374
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000375 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000376
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000377 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
378
379 for (int i = 0; i < count; i++)
380 {
381 target[0] = v[0];
382 target[1] = v[1];
383 target[2] = 0;
384 target[3] = 0;
385 target += 4;
386 v += 2;
387 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000388 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000389 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000390 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000391 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000392
393 if (arraySize == 1 && count > 1)
394 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
395
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000396 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
397
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000398 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000399
400 for (int i = 0; i < count * 2; ++i)
401 {
402 if (v[i] == 0.0f)
403 {
404 boolParams[i] = GL_FALSE;
405 }
406 else
407 {
408 boolParams[i] = GL_TRUE;
409 }
410 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000411 }
412 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413 {
414 return false;
415 }
416
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000417 return true;
418}
419
420bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
421{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000422 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000423 {
424 return false;
425 }
426
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000427 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000428 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000429
430 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000431 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000432 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000433
434 if (arraySize == 1 && count > 1)
435 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
436
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000437 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000438
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000439 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
440
441 for (int i = 0; i < count; i++)
442 {
443 target[0] = v[0];
444 target[1] = v[1];
445 target[2] = v[2];
446 target[3] = 0;
447 target += 4;
448 v += 3;
449 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000450 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000451 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000452 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000453 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000454
455 if (arraySize == 1 && count > 1)
456 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
457
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000458 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000459 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000460
461 for (int i = 0; i < count * 3; ++i)
462 {
463 if (v[i] == 0.0f)
464 {
465 boolParams[i] = GL_FALSE;
466 }
467 else
468 {
469 boolParams[i] = GL_TRUE;
470 }
471 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000472 }
473 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000474 {
475 return false;
476 }
477
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000478 return true;
479}
480
481bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
482{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000483 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000484 {
485 return false;
486 }
487
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000488 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000489 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000490
491 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000492 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000493 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000494
495 if (arraySize == 1 && count > 1)
496 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
497
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000498 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000499
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000500 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
501 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000502 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000503 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000504 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000505 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000506
507 if (arraySize == 1 && count > 1)
508 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
509
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000510 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000511 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000512
513 for (int i = 0; i < count * 4; ++i)
514 {
515 if (v[i] == 0.0f)
516 {
517 boolParams[i] = GL_FALSE;
518 }
519 else
520 {
521 boolParams[i] = GL_TRUE;
522 }
523 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000524 }
525 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000526 {
527 return false;
528 }
529
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000530 return true;
531}
532
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000533template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
534void transposeMatrix(T *target, const GLfloat *value)
535{
536 int copyWidth = std::min(targetWidth, srcWidth);
537 int copyHeight = std::min(targetHeight, srcHeight);
538
539 for (int x = 0; x < copyWidth; x++)
540 {
541 for (int y = 0; y < copyHeight; y++)
542 {
daniel@transgaming.comc9d81a22011-11-12 03:14:30 +0000543 target[x * targetWidth + y] = (T)value[y * srcWidth + x];
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000544 }
545 }
546 // clear unfilled right side
547 for (int y = 0; y < copyHeight; y++)
548 {
549 for (int x = srcWidth; x < targetWidth; x++)
550 {
daniel@transgaming.comc9d81a22011-11-12 03:14:30 +0000551 target[y * targetWidth + x] = (T)0;
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000552 }
553 }
554 // clear unfilled bottom.
555 for (int y = srcHeight; y < targetHeight; y++)
556 {
557 for (int x = 0; x < targetWidth; x++)
558 {
daniel@transgaming.comc9d81a22011-11-12 03:14:30 +0000559 target[y * targetWidth + x] = (T)0;
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000560 }
561 }
562}
563
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000564bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
565{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000566 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000567 {
568 return false;
569 }
570
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000571 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000572 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000573
574 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000575 {
576 return false;
577 }
578
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000579 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000580
581 if (arraySize == 1 && count > 1)
582 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
583
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000584 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000585
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000586 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
587 for (int i = 0; i < count; i++)
588 {
589 transposeMatrix<GLfloat,4,2,2,2>(target, value);
590 target += 8;
591 value += 4;
592 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000593
594 return true;
595}
596
597bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
598{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000599 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000600 {
601 return false;
602 }
603
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000604 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000605 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000606
607 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000608 {
609 return false;
610 }
611
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000612 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000613
614 if (arraySize == 1 && count > 1)
615 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
616
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000617 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000618
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000619 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
620 for (int i = 0; i < count; i++)
621 {
622 transposeMatrix<GLfloat,4,3,3,3>(target, value);
623 target += 12;
624 value += 9;
625 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000626
627 return true;
628}
629
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000630
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000631bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
632{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000633 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000634 {
635 return false;
636 }
637
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000638 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000639 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000640
641 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000642 {
643 return false;
644 }
645
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000646 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000647
648 if (arraySize == 1 && count > 1)
649 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
650
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000651 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000652
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000653 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
654 for (int i = 0; i < count; i++)
655 {
656 transposeMatrix<GLfloat,4,4,4,4>(target, value);
657 target += 16;
658 value += 16;
659 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000660
661 return true;
662}
663
664bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
665{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000666 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000667 {
668 return false;
669 }
670
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000671 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000672 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000673
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +0000674 if (targetUniform->type == GL_INT ||
675 targetUniform->type == GL_SAMPLER_2D ||
676 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000677 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000678 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000679
680 if (arraySize == 1 && count > 1)
681 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
682
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000683 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000684
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000685 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
686 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000687 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000688 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000689 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000690 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000691
692 if (arraySize == 1 && count > 1)
693 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
694
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000695 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000696 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000697
698 for (int i = 0; i < count; ++i)
699 {
700 if (v[i] == 0)
701 {
702 boolParams[i] = GL_FALSE;
703 }
704 else
705 {
706 boolParams[i] = GL_TRUE;
707 }
708 }
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000709 }
710 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000711 {
712 return false;
713 }
714
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000715 return true;
716}
717
718bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
719{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000720 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000721 {
722 return false;
723 }
724
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000725 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000726 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000727
728 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000729 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000730 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000731
732 if (arraySize == 1 && count > 1)
733 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
734
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000735 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000736
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000737 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
738 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000739 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000740 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000741 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000742 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000743
744 if (arraySize == 1 && count > 1)
745 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
746
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000747 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000748 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000749
750 for (int i = 0; i < count * 2; ++i)
751 {
752 if (v[i] == 0)
753 {
754 boolParams[i] = GL_FALSE;
755 }
756 else
757 {
758 boolParams[i] = GL_TRUE;
759 }
760 }
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000761 }
762 else
763 {
764 return false;
765 }
766
767 return true;
768}
769
770bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
771{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000772 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000773 {
774 return false;
775 }
776
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000777 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000778 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000779
780 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000781 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000782 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000783
784 if (arraySize == 1 && count > 1)
785 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
786
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000787 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000788
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000789 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
790 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000791 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000792 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000793 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000794 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000795
796 if (arraySize == 1 && count > 1)
797 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
798
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000799 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000800 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000801
802 for (int i = 0; i < count * 3; ++i)
803 {
804 if (v[i] == 0)
805 {
806 boolParams[i] = GL_FALSE;
807 }
808 else
809 {
810 boolParams[i] = GL_TRUE;
811 }
812 }
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000813 }
814 else
815 {
816 return false;
817 }
818
819 return true;
820}
821
822bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
823{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000824 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000825 {
826 return false;
827 }
828
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000829 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000830 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000831
832 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000833 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000834 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000835
836 if (arraySize == 1 && count > 1)
837 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
838
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000839 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000840
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000841 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
842 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000843 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000844 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000845 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000846 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000847
848 if (arraySize == 1 && count > 1)
849 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
850
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000851 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +0000852 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000853
854 for (int i = 0; i < count * 4; ++i)
855 {
856 if (v[i] == 0)
857 {
858 boolParams[i] = GL_FALSE;
859 }
860 else
861 {
862 boolParams[i] = GL_TRUE;
863 }
864 }
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000865 }
866 else
867 {
868 return false;
869 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000870
871 return true;
872}
873
daniel@transgaming.com9a849122011-11-12 03:18:00 +0000874bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000875{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000876 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000877 {
878 return false;
879 }
880
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000881 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000882
daniel@transgaming.com9a849122011-11-12 03:18:00 +0000883 // sized queries -- ensure the provided buffer is large enough
884 if (bufSize)
885 {
886 int requiredBytes = UniformExternalSize(targetUniform->type);
887 if (*bufSize < requiredBytes)
888 {
889 return false;
890 }
891 }
892
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000893 switch (targetUniform->type)
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000894 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000895 case GL_FLOAT_MAT2:
896 transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
897 break;
898 case GL_FLOAT_MAT3:
899 transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
900 break;
901 case GL_FLOAT_MAT4:
902 transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
903 break;
904 default:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000905 {
daniel@transgaming.comedc31502011-11-12 03:14:56 +0000906 unsigned int count = UniformExternalComponentCount(targetUniform->type);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000907 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000908
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000909 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000910 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000911 case GL_BOOL:
912 {
913 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * internalCount;
914
915 for (unsigned int i = 0; i < count; ++i)
916 {
917 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
918 }
919 }
920 break;
921 case GL_FLOAT:
922 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLfloat),
923 count * sizeof(GLfloat));
924 break;
925 case GL_INT:
926 {
927 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * internalCount;
928
929 for (unsigned int i = 0; i < count; ++i)
930 {
931 params[i] = (float)intParams[i];
932 }
933 }
934 break;
935 default: UNREACHABLE();
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000936 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000937 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000938 }
939
940 return true;
941}
942
daniel@transgaming.com9a849122011-11-12 03:18:00 +0000943bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000944{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000945 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000946 {
947 return false;
948 }
949
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000950 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000951
daniel@transgaming.com9a849122011-11-12 03:18:00 +0000952 // sized queries -- ensure the provided buffer is large enough
953 if (bufSize)
954 {
955 int requiredBytes = UniformExternalSize(targetUniform->type);
956 if (*bufSize < requiredBytes)
957 {
958 return false;
959 }
960 }
961
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000962 switch (targetUniform->type)
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000963 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000964 case GL_FLOAT_MAT2:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000965 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000966 transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000967 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000968 break;
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000969 case GL_FLOAT_MAT3:
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000970 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000971 transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000972 }
973 break;
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000974 case GL_FLOAT_MAT4:
975 {
976 transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
977 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000978 break;
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000979 default:
980 {
daniel@transgaming.comedc31502011-11-12 03:14:56 +0000981 unsigned int count = UniformExternalComponentCount(targetUniform->type);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +0000982 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
983
984 switch (UniformComponentType(targetUniform->type))
985 {
986 case GL_BOOL:
987 {
988 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * internalCount;
989
990 for (unsigned int i = 0; i < count; ++i)
991 {
992 params[i] = (GLint)boolParams[i];
993 }
994 }
995 break;
996 case GL_FLOAT:
997 {
998 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * internalCount;
999
1000 for (unsigned int i = 0; i < count; ++i)
1001 {
1002 params[i] = (GLint)floatParams[i];
1003 }
1004 }
1005 break;
1006 case GL_INT:
1007 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLint),
1008 count * sizeof(GLint));
1009 break;
1010 default: UNREACHABLE();
1011 }
1012 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +00001013 }
1014
1015 return true;
1016}
1017
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00001018void Program::dirtyAllUniforms()
1019{
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00001020 unsigned int numUniforms = mUniforms.size();
1021 for (unsigned int index = 0; index < numUniforms; index++)
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00001022 {
1023 mUniforms[index]->dirty = true;
1024 }
1025}
1026
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001027// Applies all the uniforms set for this program object to the Direct3D 9 device
1028void Program::applyUniforms()
1029{
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00001030 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) {
1031 Uniform *targetUniform = *ub;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001032
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00001033 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001034 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00001035 int arraySize = targetUniform->arraySize;
1036 GLfloat *f = (GLfloat*)targetUniform->data;
1037 GLint *i = (GLint*)targetUniform->data;
1038 GLboolean *b = (GLboolean*)targetUniform->data;
1039
1040 switch (targetUniform->type)
1041 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00001042 case GL_BOOL: applyUniformnbv(targetUniform, arraySize, 1, b); break;
1043 case GL_BOOL_VEC2: applyUniformnbv(targetUniform, arraySize, 2, b); break;
1044 case GL_BOOL_VEC3: applyUniformnbv(targetUniform, arraySize, 3, b); break;
1045 case GL_BOOL_VEC4: applyUniformnbv(targetUniform, arraySize, 4, b); break;
1046 case GL_FLOAT:
1047 case GL_FLOAT_VEC2:
1048 case GL_FLOAT_VEC3:
1049 case GL_FLOAT_VEC4:
1050 case GL_FLOAT_MAT2:
1051 case GL_FLOAT_MAT3:
1052 case GL_FLOAT_MAT4: applyUniformnfv(targetUniform, f); break;
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001053 case GL_SAMPLER_2D:
1054 case GL_SAMPLER_CUBE:
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00001055 case GL_INT: applyUniform1iv(targetUniform, arraySize, i); break;
1056 case GL_INT_VEC2: applyUniform2iv(targetUniform, arraySize, i); break;
1057 case GL_INT_VEC3: applyUniform3iv(targetUniform, arraySize, i); break;
1058 case GL_INT_VEC4: applyUniform4iv(targetUniform, arraySize, i); break;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00001059 default:
1060 UNREACHABLE();
1061 }
1062
1063 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001064 }
1065 }
1066}
1067
1068// Compiles the HLSL code of the attached shaders into executable binaries
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001069ID3D10Blob *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001070{
1071 if (!hlsl)
1072 {
1073 return NULL;
1074 }
1075
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001076 DWORD result;
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001077 UINT flags = 0;
1078 std::string sourceText;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001079 if (perfActive())
1080 {
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001081 flags |= D3DCOMPILE_DEBUG;
1082#ifdef NDEBUG
1083 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1084#else
1085 flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001086#endif
1087
1088 std::string sourcePath = getTempPath();
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001089 sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001090 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001091 }
1092 else
1093 {
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001094 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1095 sourceText = hlsl;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001096 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001097
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001098 ID3D10Blob *binary = NULL;
1099 ID3D10Blob *errorMessage = NULL;
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00001100 result = D3DCompile(hlsl, strlen(hlsl), fakepath, NULL, NULL, "main", profile, flags, 0, &binary, &errorMessage);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001101
1102 if (errorMessage)
1103 {
1104 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001105
daniel@transgaming.com87891f72011-06-01 15:28:35 +00001106 appendToInfoLogSanitized(message);
daniel@transgaming.com0599dc62010-03-21 04:31:36 +00001107 TRACE("\n%s", hlsl);
1108 TRACE("\n%s", message);
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001109
1110 errorMessage->Release();
1111 errorMessage = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001112 }
1113
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001114 if (FAILED(result))
1115 {
1116 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1117 {
1118 error(GL_OUT_OF_MEMORY);
1119 }
1120
1121 return NULL;
1122 }
1123
1124 result = D3DXGetShaderConstantTable(static_cast<const DWORD*>(binary->GetBufferPointer()), constantTable);
1125
1126 if (FAILED(result))
1127 {
1128 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1129 {
1130 error(GL_OUT_OF_MEMORY);
1131 }
1132
1133 binary->Release();
1134
1135 return NULL;
1136 }
1137
1138 return binary;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001139}
1140
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001141// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1142// Returns the number of used varying registers, or -1 if unsuccesful
1143int Program::packVaryings(const Varying *packing[][4])
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001144{
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001145 Context *context = getContext();
1146 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1147
daniel@transgaming.comcde6a612012-02-17 18:01:10 +00001148 for (VaryingList::iterator varying = mFragmentShader->mVaryings.begin(); varying != mFragmentShader->mVaryings.end(); varying++)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001149 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001150 int n = VariableRowCount(varying->type) * varying->size;
1151 int m = VariableColumnCount(varying->type);
1152 bool success = false;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001153
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001154 if (m == 2 || m == 3 || m == 4)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001155 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001156 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001157 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001158 bool available = true;
1159
1160 for (int y = 0; y < n && available; y++)
1161 {
1162 for (int x = 0; x < m && available; x++)
1163 {
1164 if (packing[r + y][x])
1165 {
1166 available = false;
1167 }
1168 }
1169 }
1170
1171 if (available)
1172 {
1173 varying->reg = r;
1174 varying->col = 0;
1175
1176 for (int y = 0; y < n; y++)
1177 {
1178 for (int x = 0; x < m; x++)
1179 {
1180 packing[r + y][x] = &*varying;
1181 }
1182 }
1183
1184 success = true;
1185 }
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00001186 }
1187
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001188 if (!success && m == 2)
1189 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001190 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001191 {
1192 bool available = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001193
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001194 for (int y = 0; y < n && available; y++)
1195 {
1196 for (int x = 2; x < 4 && available; x++)
1197 {
1198 if (packing[r + y][x])
1199 {
1200 available = false;
1201 }
1202 }
1203 }
1204
1205 if (available)
1206 {
1207 varying->reg = r;
1208 varying->col = 2;
1209
1210 for (int y = 0; y < n; y++)
1211 {
1212 for (int x = 2; x < 4; x++)
1213 {
1214 packing[r + y][x] = &*varying;
1215 }
1216 }
1217
1218 success = true;
1219 }
1220 }
1221 }
1222 }
1223 else if (m == 1)
1224 {
1225 int space[4] = {0};
1226
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001227 for (int y = 0; y < maxVaryingVectors; y++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001228 {
1229 for (int x = 0; x < 4; x++)
1230 {
1231 space[x] += packing[y][x] ? 0 : 1;
1232 }
1233 }
1234
1235 int column = 0;
1236
1237 for (int x = 0; x < 4; x++)
1238 {
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001239 if (space[x] >= n && space[x] < space[column])
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001240 {
1241 column = x;
1242 }
1243 }
1244
daniel@transgaming.com11dd5dd2011-02-11 13:28:14 +00001245 if (space[column] >= n)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001246 {
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001247 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001248 {
1249 if (!packing[r][column])
1250 {
1251 varying->reg = r;
1252
1253 for (int y = r; y < r + n; y++)
1254 {
1255 packing[y][column] = &*varying;
1256 }
1257
1258 break;
1259 }
1260 }
1261
1262 varying->col = column;
1263
1264 success = true;
1265 }
1266 }
1267 else UNREACHABLE();
1268
1269 if (!success)
1270 {
1271 appendToInfoLog("Could not pack varying %s", varying->name.c_str());
1272
1273 return -1;
1274 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001275 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001276
1277 // Return the number of used registers
1278 int registers = 0;
1279
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001280 for (int r = 0; r < maxVaryingVectors; r++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001281 {
1282 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1283 {
1284 registers++;
1285 }
1286 }
1287
1288 return registers;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001289}
1290
1291bool Program::linkVaryings()
1292{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001293 if (mPixelHLSL.empty() || mVertexHLSL.empty())
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001294 {
1295 return false;
1296 }
1297
daniel@transgaming.com97750022011-02-11 13:23:13 +00001298 // Reset the varying register assignments
daniel@transgaming.comcde6a612012-02-17 18:01:10 +00001299 for (VaryingList::iterator fragVar = mFragmentShader->mVaryings.begin(); fragVar != mFragmentShader->mVaryings.end(); fragVar++)
daniel@transgaming.com97750022011-02-11 13:23:13 +00001300 {
1301 fragVar->reg = -1;
1302 fragVar->col = -1;
1303 }
1304
daniel@transgaming.comcde6a612012-02-17 18:01:10 +00001305 for (VaryingList::iterator vtxVar = mVertexShader->mVaryings.begin(); vtxVar != mVertexShader->mVaryings.end(); vtxVar++)
daniel@transgaming.com97750022011-02-11 13:23:13 +00001306 {
1307 vtxVar->reg = -1;
1308 vtxVar->col = -1;
1309 }
1310
1311 // Map the varyings to the register file
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001312 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001313 int registers = packVaryings(packing);
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001314
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001315 if (registers < 0)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001316 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001317 return false;
1318 }
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001319
daniel@transgaming.com97750022011-02-11 13:23:13 +00001320 // Write the HLSL input/output declarations
daniel@transgaming.com396c6432010-11-26 16:26:12 +00001321 Context *context = getContext();
1322 const bool sm3 = context->supportsShaderModel3();
1323 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1324
1325 if (registers == maxVaryingVectors && mFragmentShader->mUsesFragCoord)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001326 {
1327 appendToInfoLog("No varying registers left to support gl_FragCoord");
1328
1329 return false;
1330 }
1331
daniel@transgaming.comcde6a612012-02-17 18:01:10 +00001332 for (VaryingList::iterator input = mFragmentShader->mVaryings.begin(); input != mFragmentShader->mVaryings.end(); input++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001333 {
1334 bool matched = false;
1335
daniel@transgaming.comcde6a612012-02-17 18:01:10 +00001336 for (VaryingList::iterator output = mVertexShader->mVaryings.begin(); output != mVertexShader->mVaryings.end(); output++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001337 {
1338 if (output->name == input->name)
1339 {
1340 if (output->type != input->type || output->size != input->size)
1341 {
1342 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
1343
1344 return false;
1345 }
1346
1347 output->reg = input->reg;
1348 output->col = input->col;
1349
1350 matched = true;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001351 break;
1352 }
1353 }
1354
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001355 if (!matched)
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001356 {
daniel@transgaming.com97750022011-02-11 13:23:13 +00001357 appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001358
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001359 return false;
1360 }
1361 }
1362
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001363 std::string varyingSemantic = (sm3 ? "COLOR" : "TEXCOORD");
1364
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001365 mVertexHLSL += "struct VS_INPUT\n"
1366 "{\n";
1367
1368 int semanticIndex = 0;
1369 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1370 {
1371 switch (attribute->type)
1372 {
1373 case GL_FLOAT: mVertexHLSL += " float "; break;
1374 case GL_FLOAT_VEC2: mVertexHLSL += " float2 "; break;
1375 case GL_FLOAT_VEC3: mVertexHLSL += " float3 "; break;
1376 case GL_FLOAT_VEC4: mVertexHLSL += " float4 "; break;
1377 case GL_FLOAT_MAT2: mVertexHLSL += " float2x2 "; break;
1378 case GL_FLOAT_MAT3: mVertexHLSL += " float3x3 "; break;
1379 case GL_FLOAT_MAT4: mVertexHLSL += " float4x4 "; break;
1380 default: UNREACHABLE();
1381 }
1382
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001383 mVertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001384
1385 semanticIndex += VariableRowCount(attribute->type);
1386 }
1387
1388 mVertexHLSL += "};\n"
1389 "\n"
1390 "struct VS_OUTPUT\n"
1391 "{\n"
1392 " float4 gl_Position : POSITION;\n";
1393
1394 for (int r = 0; r < registers; r++)
1395 {
1396 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1397
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001398 mVertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001399 }
1400
1401 if (mFragmentShader->mUsesFragCoord)
1402 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001403 mVertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1404 }
1405
1406 if (mVertexShader->mUsesPointSize && sm3)
1407 {
1408 mVertexHLSL += " float gl_PointSize : PSIZE;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001409 }
1410
1411 mVertexHLSL += "};\n"
1412 "\n"
1413 "VS_OUTPUT main(VS_INPUT input)\n"
1414 "{\n";
1415
1416 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
1417 {
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001418 mVertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001419
1420 if (VariableRowCount(attribute->type) > 1) // Matrix
1421 {
1422 mVertexHLSL += "transpose";
1423 }
1424
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001425 mVertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001426 }
1427
1428 mVertexHLSL += "\n"
1429 " gl_main();\n"
1430 "\n"
1431 " VS_OUTPUT output;\n"
1432 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001433 " output.gl_Position.y = gl_Position.y - dx_HalfPixelSize.y * gl_Position.w;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001434 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1435 " output.gl_Position.w = gl_Position.w;\n";
1436
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001437 if (mVertexShader->mUsesPointSize && sm3)
1438 {
1439 mVertexHLSL += " output.gl_PointSize = clamp(gl_PointSize, 1.0, " + str((int)ALIASED_POINT_SIZE_RANGE_MAX_SM3) + ");\n";
1440 }
1441
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001442 if (mFragmentShader->mUsesFragCoord)
1443 {
1444 mVertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1445 }
1446
daniel@transgaming.comcde6a612012-02-17 18:01:10 +00001447 for (VaryingList::iterator varying = mVertexShader->mVaryings.begin(); varying != mVertexShader->mVaryings.end(); varying++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001448 {
1449 if (varying->reg >= 0)
1450 {
1451 for (int i = 0; i < varying->size; i++)
1452 {
1453 int rows = VariableRowCount(varying->type);
1454
1455 for (int j = 0; j < rows; j++)
1456 {
1457 int r = varying->reg + i * rows + j;
1458 mVertexHLSL += " output.v" + str(r);
1459
1460 bool sharedRegister = false; // Register used by multiple varyings
1461
1462 for (int x = 0; x < 4; x++)
1463 {
1464 if (packing[r][x] && packing[r][x] != packing[r][0])
1465 {
1466 sharedRegister = true;
1467 break;
1468 }
1469 }
1470
1471 if(sharedRegister)
1472 {
1473 mVertexHLSL += ".";
1474
1475 for (int x = 0; x < 4; x++)
1476 {
1477 if (packing[r][x] == &*varying)
1478 {
1479 switch(x)
1480 {
1481 case 0: mVertexHLSL += "x"; break;
1482 case 1: mVertexHLSL += "y"; break;
1483 case 2: mVertexHLSL += "z"; break;
1484 case 3: mVertexHLSL += "w"; break;
1485 }
1486 }
1487 }
1488 }
1489
1490 mVertexHLSL += " = " + varying->name;
1491
1492 if (varying->array)
1493 {
1494 mVertexHLSL += "[" + str(i) + "]";
1495 }
1496
1497 if (rows > 1)
1498 {
1499 mVertexHLSL += "[" + str(j) + "]";
1500 }
1501
1502 mVertexHLSL += ";\n";
1503 }
1504 }
1505 }
1506 }
1507
1508 mVertexHLSL += "\n"
1509 " return output;\n"
1510 "}\n";
1511
1512 mPixelHLSL += "struct PS_INPUT\n"
1513 "{\n";
1514
daniel@transgaming.comcde6a612012-02-17 18:01:10 +00001515 for (VaryingList::iterator varying = mFragmentShader->mVaryings.begin(); varying != mFragmentShader->mVaryings.end(); varying++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001516 {
1517 if (varying->reg >= 0)
1518 {
1519 for (int i = 0; i < varying->size; i++)
1520 {
1521 int rows = VariableRowCount(varying->type);
1522 for (int j = 0; j < rows; j++)
1523 {
1524 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001525 mPixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001526 }
1527 }
1528 }
1529 else UNREACHABLE();
1530 }
1531
1532 if (mFragmentShader->mUsesFragCoord)
1533 {
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001534 mPixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001535 if (sm3) {
daniel@transgaming.com996675c2010-11-17 13:06:29 +00001536 mPixelHLSL += " float2 dx_VPos : VPOS;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001537 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001538 }
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001539
1540 if (mFragmentShader->mUsesPointCoord && sm3)
1541 {
1542 mPixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1543 }
1544
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001545 if (mFragmentShader->mUsesFrontFacing)
1546 {
1547 mPixelHLSL += " float vFace : VFACE;\n";
1548 }
1549
1550 mPixelHLSL += "};\n"
1551 "\n"
1552 "struct PS_OUTPUT\n"
1553 "{\n"
1554 " float4 gl_Color[1] : COLOR;\n"
1555 "};\n"
1556 "\n"
1557 "PS_OUTPUT main(PS_INPUT input)\n"
1558 "{\n";
1559
1560 if (mFragmentShader->mUsesFragCoord)
1561 {
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001562 mPixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00001563
1564 if (sm3)
1565 {
1566 // dx_Coord.y contains the render target height. See Context::applyRenderTarget()
apatrick@chromium.orgb1092bf2011-05-11 19:52:39 +00001567 mPixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00001568 " gl_FragCoord.y = dx_Coord.y - input.dx_VPos.y - 0.5;\n";
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001569 }
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00001570 else
1571 {
1572 // dx_Coord contains the viewport width/2, height/2, center.x and center.y. See Context::applyRenderTarget()
1573 mPixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Coord.x + dx_Coord.z;\n"
1574 " gl_FragCoord.y = -(input.gl_FragCoord.y * rhw) * dx_Coord.y + dx_Coord.w;\n";
1575 }
1576
kbr@chromium.org72d58c42010-11-05 22:55:28 +00001577 mPixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001578 " gl_FragCoord.w = rhw;\n";
1579 }
1580
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001581 if (mFragmentShader->mUsesPointCoord && sm3)
1582 {
apatrick@chromium.orgda4d0492011-01-22 00:16:10 +00001583 mPixelHLSL += " gl_PointCoord = input.gl_PointCoord;\n";
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001584 }
1585
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001586 if (mFragmentShader->mUsesFrontFacing)
1587 {
1588 mPixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1589 }
1590
daniel@transgaming.comcde6a612012-02-17 18:01:10 +00001591 for (VaryingList::iterator varying = mFragmentShader->mVaryings.begin(); varying != mFragmentShader->mVaryings.end(); varying++)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001592 {
1593 if (varying->reg >= 0)
1594 {
1595 for (int i = 0; i < varying->size; i++)
1596 {
1597 int rows = VariableRowCount(varying->type);
1598 for (int j = 0; j < rows; j++)
1599 {
1600 std::string n = str(varying->reg + i * rows + j);
1601 mPixelHLSL += " " + varying->name;
1602
1603 if (varying->array)
1604 {
1605 mPixelHLSL += "[" + str(i) + "]";
1606 }
1607
1608 if (rows > 1)
1609 {
1610 mPixelHLSL += "[" + str(j) + "]";
1611 }
1612
1613 mPixelHLSL += " = input.v" + n + ";\n";
1614 }
1615 }
1616 }
1617 else UNREACHABLE();
1618 }
1619
1620 mPixelHLSL += "\n"
1621 " gl_main();\n"
1622 "\n"
1623 " PS_OUTPUT output;\n"
1624 " output.gl_Color[0] = gl_Color[0];\n"
1625 "\n"
1626 " return output;\n"
1627 "}\n";
1628
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001629 return true;
1630}
1631
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001632// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1633// compiling them into binaries, determining the attribute mappings, and collecting
1634// a list of uniforms
1635void Program::link()
1636{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001637 unlink();
1638
1639 if (!mFragmentShader || !mFragmentShader->isCompiled())
1640 {
1641 return;
1642 }
1643
1644 if (!mVertexShader || !mVertexShader->isCompiled())
1645 {
1646 return;
1647 }
1648
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001649 mPixelHLSL = mFragmentShader->getHLSL();
1650 mVertexHLSL = mVertexShader->getHLSL();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001651
1652 if (!linkVaryings())
1653 {
1654 return;
1655 }
1656
daniel@transgaming.combe5a0862010-07-28 19:20:37 +00001657 Context *context = getContext();
1658 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1659 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1660
apatrick@chromium.org8ea5afe2011-03-23 20:44:36 +00001661 ID3D10Blob *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1662 ID3D10Blob *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001663
1664 if (vertexBinary && pixelBinary)
1665 {
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +00001666 HRESULT vertexResult = mDevice->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1667 HRESULT pixelResult = mDevice->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001668
1669 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1670 {
1671 return error(GL_OUT_OF_MEMORY);
1672 }
1673
1674 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001675
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001676 vertexBinary->Release();
1677 pixelBinary->Release();
1678 vertexBinary = NULL;
1679 pixelBinary = NULL;
1680
1681 if (mVertexExecutable && mPixelExecutable)
1682 {
1683 if (!linkAttributes())
1684 {
1685 return;
1686 }
1687
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001688 if (!linkUniforms(GL_FRAGMENT_SHADER, mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001689 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001690 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001691 }
1692
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001693 if (!linkUniforms(GL_VERTEX_SHADER, mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001694 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001695 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001696 }
1697
daniel@transgaming.coma3bbfd42010-06-07 02:06:09 +00001698 // these uniforms are searched as already-decorated because gl_ and dx_
1699 // are reserved prefixes, and do not receive additional decoration
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001700 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
1701 mDxDepthLocation = getUniformLocation("dx_Depth");
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00001702 mDxCoordLocation = getUniformLocation("dx_Coord");
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001703 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
1704 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
1705 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00001706
daniel@transgaming.com11399d52012-04-28 00:35:14 +00001707 context->markDxUniformsDirty();
1708
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001709 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001710 }
1711 }
1712}
1713
1714// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1715bool Program::linkAttributes()
1716{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001717 unsigned int usedLocations = 0;
1718
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001719 // Link attributes that have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001720 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001721 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001722 int location = getAttributeBinding(attribute->name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001723
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001724 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001725 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001726 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001727 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001728 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001729 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001730
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001731 mLinkedAttribute[location] = *attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001732
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001733 int rows = VariableRowCount(attribute->type);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001734
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001735 if (rows + location > MAX_VERTEX_ATTRIBS)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001736 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001737 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 +00001738
1739 return false;
1740 }
1741
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001742 for (int i = 0; i < rows; i++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001743 {
1744 usedLocations |= 1 << (location + i);
1745 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001746 }
1747 }
1748
1749 // Link attributes that don't have a binding location
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001750 for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001751 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001752 int location = getAttributeBinding(attribute->name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001753
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001754 if (location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001755 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001756 int rows = VariableRowCount(attribute->type);
1757 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001758
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001759 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001760 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001761 appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001762
1763 return false; // Fail to link
1764 }
1765
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001766 mLinkedAttribute[availableIndex] = *attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001767 }
1768 }
1769
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001770 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001771 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001772 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001773 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001774
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001775 for (int r = 0; r < rows; r++)
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001776 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001777 mSemanticIndex[attributeIndex++] = index++;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001778 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001779 }
1780
1781 return true;
1782}
1783
daniel@transgaming.com85423182010-04-22 13:35:27 +00001784int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001785{
1786 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1787 {
1788 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1789 {
1790 return location;
1791 }
1792 }
1793
1794 return -1;
1795}
1796
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001797bool Program::linkUniforms(GLenum shader, ID3DXConstantTable *constantTable)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001798{
1799 D3DXCONSTANTTABLE_DESC constantTableDescription;
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001800
1801 constantTable->GetDesc(&constantTableDescription);
1802
1803 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1804 {
1805 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001806
1807 D3DXCONSTANT_DESC constantDescription;
1808 UINT descriptionCount = 1;
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001809 HRESULT result = constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1810 ASSERT(SUCCEEDED(result));
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001811
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001812 if (!defineUniform(shader, constantHandle, constantDescription))
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001813 {
1814 return false;
1815 }
1816 }
1817
1818 return true;
1819}
1820
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001821// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001822// Returns true if succesful (uniform not already defined)
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001823bool Program::defineUniform(GLenum shader, const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001824{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001825 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1826 {
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001827 for (unsigned int i = 0; i < constantDescription.RegisterCount; i++)
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001828 {
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001829 D3DXHANDLE psConstant = mConstantTablePS->GetConstantByName(NULL, constantDescription.Name);
1830 D3DXHANDLE vsConstant = mConstantTableVS->GetConstantByName(NULL, constantDescription.Name);
1831
1832 if (psConstant)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001833 {
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001834 unsigned int samplerIndex = mConstantTablePS->GetSamplerIndex(psConstant) + i;
1835
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001836 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1837 {
1838 mSamplersPS[samplerIndex].active = true;
1839 mSamplersPS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1840 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00001841 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001842 }
1843 else
1844 {
1845 appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
1846 return false;
1847 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001848 }
1849
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001850 if (vsConstant)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001851 {
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001852 unsigned int samplerIndex = mConstantTableVS->GetSamplerIndex(vsConstant) + i;
1853
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001854 if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
1855 {
1856 mSamplersVS[samplerIndex].active = true;
1857 mSamplersVS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1858 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00001859 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001860 }
1861 else
1862 {
1863 appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
1864 return false;
1865 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001866 }
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001867 }
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001868 }
1869
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001870 switch(constantDescription.Class)
1871 {
1872 case D3DXPC_STRUCT:
1873 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001874 for (unsigned int arrayIndex = 0; arrayIndex < constantDescription.Elements; arrayIndex++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001875 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001876 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001877 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001878 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1879
1880 D3DXCONSTANT_DESC fieldDescription;
1881 UINT descriptionCount = 1;
1882
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001883 HRESULT result = mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1884 ASSERT(SUCCEEDED(result));
daniel@transgaming.comce864422010-11-18 13:16:49 +00001885
1886 std::string structIndex = (constantDescription.Elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
1887
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001888 if (!defineUniform(shader, fieldHandle, fieldDescription, name + constantDescription.Name + structIndex + "."))
daniel@transgaming.comce864422010-11-18 13:16:49 +00001889 {
1890 return false;
1891 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001892 }
1893 }
1894
1895 return true;
1896 }
1897 case D3DXPC_SCALAR:
1898 case D3DXPC_VECTOR:
1899 case D3DXPC_MATRIX_COLUMNS:
1900 case D3DXPC_OBJECT:
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001901 return defineUniform(shader, constantDescription, name + constantDescription.Name);
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001902 default:
1903 UNREACHABLE();
1904 return false;
1905 }
1906}
1907
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001908bool Program::defineUniform(GLenum shader, const D3DXCONSTANT_DESC &constantDescription, const std::string &_name)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001909{
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001910 Uniform *uniform = createUniform(constantDescription, _name);
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001911
1912 if(!uniform)
1913 {
1914 return false;
1915 }
1916
1917 // Check if already defined
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001918 GLint location = getUniformLocation(uniform->name);
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001919 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001920
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001921 if (location >= 0)
1922 {
1923 delete uniform;
daniel@transgaming.comec909fc2012-06-05 19:51:49 +00001924 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001925 }
1926
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001927 if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constantDescription);
1928 if (shader == GL_VERTEX_SHADER) uniform->vs.set(constantDescription);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00001929
daniel@transgaming.comec909fc2012-06-05 19:51:49 +00001930 if (location >= 0)
1931 {
1932 return uniform->type == type;
1933 }
1934
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001935 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001936 unsigned int uniformIndex = mUniforms.size() - 1;
1937
1938 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1939 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001940 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001941 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001942
1943 return true;
1944}
1945
apatrick@chromium.orge057c5d2012-01-26 19:18:24 +00001946Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, const std::string &_name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001947{
1948 if (constantDescription.Rows == 1) // Vectors and scalars
1949 {
1950 switch (constantDescription.Type)
1951 {
1952 case D3DXPT_SAMPLER2D:
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001953 switch (constantDescription.Columns)
1954 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001955 case 1: return new Uniform(GL_SAMPLER_2D, _name, constantDescription.Elements);
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001956 default: UNREACHABLE();
1957 }
1958 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001959 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001960 switch (constantDescription.Columns)
1961 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001962 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001963 default: UNREACHABLE();
1964 }
1965 break;
1966 case D3DXPT_BOOL:
1967 switch (constantDescription.Columns)
1968 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001969 case 1: return new Uniform(GL_BOOL, _name, constantDescription.Elements);
1970 case 2: return new Uniform(GL_BOOL_VEC2, _name, constantDescription.Elements);
1971 case 3: return new Uniform(GL_BOOL_VEC3, _name, constantDescription.Elements);
1972 case 4: return new Uniform(GL_BOOL_VEC4, _name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001973 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001974 }
1975 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001976 case D3DXPT_INT:
1977 switch (constantDescription.Columns)
1978 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001979 case 1: return new Uniform(GL_INT, _name, constantDescription.Elements);
1980 case 2: return new Uniform(GL_INT_VEC2, _name, constantDescription.Elements);
1981 case 3: return new Uniform(GL_INT_VEC3, _name, constantDescription.Elements);
1982 case 4: return new Uniform(GL_INT_VEC4, _name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001983 default: UNREACHABLE();
1984 }
1985 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001986 case D3DXPT_FLOAT:
1987 switch (constantDescription.Columns)
1988 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001989 case 1: return new Uniform(GL_FLOAT, _name, constantDescription.Elements);
1990 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constantDescription.Elements);
1991 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constantDescription.Elements);
1992 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001993 default: UNREACHABLE();
1994 }
1995 break;
1996 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001997 UNREACHABLE();
1998 }
1999 }
2000 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
2001 {
2002 switch (constantDescription.Type)
2003 {
2004 case D3DXPT_FLOAT:
2005 switch (constantDescription.Rows)
2006 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002007 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constantDescription.Elements);
2008 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constantDescription.Elements);
2009 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002010 default: UNREACHABLE();
2011 }
2012 break;
2013 default: UNREACHABLE();
2014 }
2015 }
2016 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00002017
2018 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002019}
2020
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002021// This method needs to match OutputHLSL::decorate
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002022std::string Program::decorateAttribute(const std::string &name)
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002023{
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002024 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002025 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002026 return "_" + name;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002027 }
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002028
2029 return name;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002030}
2031
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002032std::string Program::undecorateUniform(const std::string &_name)
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002033{
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002034 std::string name = _name;
2035
2036 // Remove any structure field decoration
2037 size_t pos = 0;
2038 while ((pos = name.find("._", pos)) != std::string::npos)
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002039 {
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002040 name.replace(pos, 2, ".");
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002041 }
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002042
2043 // Remove the leading decoration
2044 if (name[0] == '_')
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002045 {
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002046 return name.substr(1);
2047 }
2048 else if (name.compare(0, 3, "ar_") == 0)
2049 {
2050 return name.substr(3);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002051 }
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002052
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002053 return name;
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002054}
2055
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002056void Program::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002057{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002058 float vector[D3D9_MAX_FLOAT_CONSTANTS * 4];
2059 BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS];
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002060
daniel@transgaming.com28be96b2012-06-05 19:51:46 +00002061 if (targetUniform->ps.float4Index >= 0 || targetUniform->vs.float4Index >= 0)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002062 {
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002063 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002064 for (int i = 0; i < count; i++)
2065 {
2066 for (int j = 0; j < 4; j++)
2067 {
2068 if (j < width)
2069 {
2070 vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f;
2071 }
2072 else
2073 {
2074 vector[i * 4 + j] = 0.0f;
2075 }
2076 }
2077 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002078 }
2079
daniel@transgaming.com28be96b2012-06-05 19:51:46 +00002080 if (targetUniform->ps.boolIndex >= 0 || targetUniform->vs.boolIndex >= 0)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002081 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002082 int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0;
2083 int vsCount = targetUniform->vs.boolIndex >= 0 ? targetUniform->vs.registerCount : 0;
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002084 int copyCount = std::min(count * width, std::max(psCount, vsCount));
2085 ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS);
2086 for (int i = 0; i < copyCount; i++)
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002087 {
2088 boolVector[i] = v[i] != GL_FALSE;
2089 }
2090 }
2091
daniel@transgaming.com28be96b2012-06-05 19:51:46 +00002092 if (targetUniform->ps.float4Index >= 0)
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002093 {
daniel@transgaming.com28be96b2012-06-05 19:51:46 +00002094 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002095 }
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002096
daniel@transgaming.com28be96b2012-06-05 19:51:46 +00002097 if (targetUniform->ps.boolIndex >= 0)
2098 {
2099 mDevice->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount);
2100 }
2101
2102 if (targetUniform->vs.float4Index >= 0)
2103 {
2104 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount);
2105 }
2106
2107 if (targetUniform->vs.boolIndex >= 0)
2108 {
2109 mDevice->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002110 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002111}
2112
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002113bool Program::applyUniformnfv(Uniform *targetUniform, const GLfloat *v)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002114{
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002115 if (targetUniform->ps.registerCount)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002116 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002117 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002118 }
2119
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002120 if (targetUniform->vs.registerCount)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002121 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002122 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002123 }
2124
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002125 return true;
2126}
2127
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002128bool Program::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002129{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002130 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2131 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002132
2133 for (int i = 0; i < count; i++)
2134 {
2135 vector[i] = D3DXVECTOR4((float)v[i], 0, 0, 0);
2136 }
2137
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002138 if (targetUniform->ps.registerCount)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002139 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002140 if (targetUniform->ps.samplerIndex >= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002141 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002142 unsigned int firstIndex = targetUniform->ps.samplerIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002143
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002144 for (int i = 0; i < count; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002145 {
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002146 unsigned int samplerIndex = firstIndex + i;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002147
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002148 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002149 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002150 ASSERT(mSamplersPS[samplerIndex].active);
2151 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002152 }
2153 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002154 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002155 else
2156 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002157 ASSERT(targetUniform->ps.float4Index >= 0);
2158 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount);
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002159 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002160 }
2161
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002162 if (targetUniform->vs.registerCount)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002163 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002164 if (targetUniform->vs.samplerIndex >= 0)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002165 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002166 unsigned int firstIndex = targetUniform->vs.samplerIndex;
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002167
2168 for (int i = 0; i < count; i++)
2169 {
2170 unsigned int samplerIndex = firstIndex + i;
2171
2172 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2173 {
2174 ASSERT(mSamplersVS[samplerIndex].active);
2175 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2176 }
2177 }
2178 }
2179 else
2180 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002181 ASSERT(targetUniform->vs.float4Index >= 0);
2182 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002183 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002184 }
2185
2186 return true;
2187}
2188
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002189bool Program::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002190{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002191 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2192 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002193
2194 for (int i = 0; i < count; i++)
2195 {
2196 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2197
2198 v += 2;
2199 }
2200
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002201 applyUniformniv(targetUniform, count, vector);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002202
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002203 return true;
2204}
2205
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002206bool Program::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002207{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002208 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2209 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002210
2211 for (int i = 0; i < count; i++)
2212 {
2213 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2214
2215 v += 3;
2216 }
2217
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002218 applyUniformniv(targetUniform, count, vector);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002219
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002220 return true;
2221}
2222
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002223bool Program::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002224{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002225 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2226 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002227
2228 for (int i = 0; i < count; i++)
2229 {
2230 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2231
2232 v += 4;
2233 }
2234
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002235 applyUniformniv(targetUniform, count, vector);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002236
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002237 return true;
2238}
2239
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002240void Program::applyUniformniv(Uniform *targetUniform, GLsizei count, const D3DXVECTOR4 *vector)
2241{
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002242 if (targetUniform->ps.registerCount)
2243 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002244 ASSERT(targetUniform->ps.float4Index >= 0);
2245 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002246 }
2247
2248 if (targetUniform->vs.registerCount)
2249 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002250 ASSERT(targetUniform->vs.float4Index >= 0);
2251 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002252 }
2253}
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002254
2255// append a santized message to the program info log.
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002256// The D3D compiler includes a fake file path in some of the warning or error
2257// messages, so lets remove all occurrences of this fake file path from the log.
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002258void Program::appendToInfoLogSanitized(const char *message)
2259{
2260 std::string msg(message);
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002261
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002262 size_t found;
2263 do
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002264 {
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002265 found = msg.find(fakepath);
2266 if (found != std::string::npos)
2267 {
2268 msg.erase(found, strlen(fakepath));
2269 }
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002270 }
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002271 while (found != std::string::npos);
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002272
2273 appendToInfoLog("%s\n", msg.c_str());
2274}
2275
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002276void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002277{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002278 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002279 {
2280 return;
2281 }
2282
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002283 char info[1024];
2284
2285 va_list vararg;
2286 va_start(vararg, format);
2287 vsnprintf(info, sizeof(info), format, vararg);
2288 va_end(vararg);
2289
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002290 size_t infoLength = strlen(info);
2291
2292 if (!mInfoLog)
2293 {
2294 mInfoLog = new char[infoLength + 1];
2295 strcpy(mInfoLog, info);
2296 }
2297 else
2298 {
2299 size_t logLength = strlen(mInfoLog);
2300 char *newLog = new char[logLength + infoLength + 1];
2301 strcpy(newLog, mInfoLog);
2302 strcpy(newLog + logLength, info);
2303
2304 delete[] mInfoLog;
2305 mInfoLog = newLog;
2306 }
2307}
2308
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002309void Program::resetInfoLog()
2310{
2311 if (mInfoLog)
2312 {
2313 delete [] mInfoLog;
daniel@transgaming.com6a20d102010-08-31 13:54:27 +00002314 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002315 }
2316}
2317
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +00002318// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002319void Program::unlink(bool destroy)
2320{
2321 if (destroy) // Object being destructed
2322 {
2323 if (mFragmentShader)
2324 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002325 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002326 mFragmentShader = NULL;
2327 }
2328
2329 if (mVertexShader)
2330 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002331 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002332 mVertexShader = NULL;
2333 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002334 }
2335
2336 if (mPixelExecutable)
2337 {
2338 mPixelExecutable->Release();
2339 mPixelExecutable = NULL;
2340 }
2341
2342 if (mVertexExecutable)
2343 {
2344 mVertexExecutable->Release();
2345 mVertexExecutable = NULL;
2346 }
2347
2348 if (mConstantTablePS)
2349 {
2350 mConstantTablePS->Release();
2351 mConstantTablePS = NULL;
2352 }
2353
2354 if (mConstantTableVS)
2355 {
2356 mConstantTableVS->Release();
2357 mConstantTableVS = NULL;
2358 }
2359
2360 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2361 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002362 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002363 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002364 }
2365
2366 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2367 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002368 mSamplersPS[index].active = false;
2369 }
2370
2371 for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
2372 {
2373 mSamplersVS[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002374 }
2375
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00002376 mUsedVertexSamplerRange = 0;
2377 mUsedPixelSamplerRange = 0;
2378
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002379 while (!mUniforms.empty())
2380 {
2381 delete mUniforms.back();
2382 mUniforms.pop_back();
2383 }
2384
daniel@transgaming.com31754962010-11-28 02:02:52 +00002385 mDxDepthRangeLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002386 mDxDepthLocation = -1;
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00002387 mDxCoordLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002388 mDxHalfPixelSizeLocation = -1;
2389 mDxFrontCCWLocation = -1;
2390 mDxPointsOrLinesLocation = -1;
2391
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002392 mUniformIndex.clear();
2393
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002394 mPixelHLSL.clear();
2395 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002396
2397 delete[] mInfoLog;
2398 mInfoLog = NULL;
2399
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002400 mLinked = false;
2401}
2402
2403bool Program::isLinked()
2404{
2405 return mLinked;
2406}
2407
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002408bool Program::isValidated() const
2409{
2410 return mValidated;
2411}
2412
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002413void Program::release()
2414{
2415 mRefCount--;
2416
2417 if (mRefCount == 0 && mDeleteStatus)
2418 {
2419 mResourceManager->deleteProgram(mHandle);
2420 }
2421}
2422
2423void Program::addRef()
2424{
2425 mRefCount++;
2426}
2427
2428unsigned int Program::getRefCount() const
2429{
2430 return mRefCount;
2431}
2432
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002433unsigned int Program::getSerial() const
2434{
2435 return mSerial;
2436}
2437
2438unsigned int Program::issueSerial()
2439{
2440 return mCurrentSerial++;
2441}
2442
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002443int Program::getInfoLogLength() const
2444{
2445 if (!mInfoLog)
2446 {
2447 return 0;
2448 }
2449 else
2450 {
2451 return strlen(mInfoLog) + 1;
2452 }
2453}
2454
2455void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2456{
2457 int index = 0;
2458
daniel@transgaming.com807d8c32012-04-04 15:06:04 +00002459 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002460 {
daniel@transgaming.com807d8c32012-04-04 15:06:04 +00002461 if (mInfoLog)
2462 {
2463 index = std::min(bufSize - 1, (int)strlen(mInfoLog));
2464 memcpy(infoLog, mInfoLog, index);
2465 }
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002466
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002467 infoLog[index] = '\0';
2468 }
2469
2470 if (length)
2471 {
2472 *length = index;
2473 }
2474}
2475
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002476void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2477{
2478 int total = 0;
2479
2480 if (mVertexShader)
2481 {
2482 if (total < maxCount)
2483 {
2484 shaders[total] = mVertexShader->getHandle();
2485 }
2486
2487 total++;
2488 }
2489
2490 if (mFragmentShader)
2491 {
2492 if (total < maxCount)
2493 {
2494 shaders[total] = mFragmentShader->getHandle();
2495 }
2496
2497 total++;
2498 }
2499
2500 if (count)
2501 {
2502 *count = total;
2503 }
2504}
2505
daniel@transgaming.com85423182010-04-22 13:35:27 +00002506void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2507{
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002508 // Skip over inactive attributes
2509 unsigned int activeAttribute = 0;
2510 unsigned int attribute;
2511 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
daniel@transgaming.com85423182010-04-22 13:35:27 +00002512 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002513 if (mLinkedAttribute[attribute].name.empty())
daniel@transgaming.com85423182010-04-22 13:35:27 +00002514 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002515 continue;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002516 }
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002517
2518 if (activeAttribute == index)
2519 {
2520 break;
2521 }
2522
2523 activeAttribute++;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002524 }
2525
2526 if (bufsize > 0)
2527 {
2528 const char *string = mLinkedAttribute[attribute].name.c_str();
2529
2530 strncpy(name, string, bufsize);
2531 name[bufsize - 1] = '\0';
2532
2533 if (length)
2534 {
2535 *length = strlen(name);
2536 }
2537 }
2538
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002539 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002540
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002541 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002542}
2543
2544GLint Program::getActiveAttributeCount()
2545{
2546 int count = 0;
2547
2548 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2549 {
2550 if (!mLinkedAttribute[attributeIndex].name.empty())
2551 {
2552 count++;
2553 }
2554 }
2555
2556 return count;
2557}
2558
2559GLint Program::getActiveAttributeMaxLength()
2560{
2561 int maxLength = 0;
2562
2563 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2564 {
2565 if (!mLinkedAttribute[attributeIndex].name.empty())
2566 {
2567 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2568 }
2569 }
2570
2571 return maxLength;
2572}
2573
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002574void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2575{
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002576 // Skip over internal uniforms
2577 unsigned int activeUniform = 0;
2578 unsigned int uniform;
2579 for (uniform = 0; uniform < mUniforms.size(); uniform++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002580 {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002581 if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002582 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002583 continue;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002584 }
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002585
2586 if (activeUniform == index)
2587 {
2588 break;
2589 }
2590
2591 activeUniform++;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002592 }
2593
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002594 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2595
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002596 if (bufsize > 0)
2597 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002598 std::string string = mUniforms[uniform]->name;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002599
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002600 if (mUniforms[uniform]->isArray())
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002601 {
2602 string += "[0]";
2603 }
2604
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002605 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002606 name[bufsize - 1] = '\0';
2607
2608 if (length)
2609 {
2610 *length = strlen(name);
2611 }
2612 }
2613
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002614 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002615
2616 *type = mUniforms[uniform]->type;
2617}
2618
2619GLint Program::getActiveUniformCount()
2620{
2621 int count = 0;
2622
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002623 unsigned int numUniforms = mUniforms.size();
2624 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002625 {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002626 if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002627 {
2628 count++;
2629 }
2630 }
2631
2632 return count;
2633}
2634
2635GLint Program::getActiveUniformMaxLength()
2636{
2637 int maxLength = 0;
2638
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002639 unsigned int numUniforms = mUniforms.size();
2640 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002641 {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002642 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002643 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002644 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2645 if (mUniforms[uniformIndex]->isArray())
zmo@google.com53d73e02011-03-24 21:27:57 +00002646 {
2647 length += 3; // Counting in "[0]".
2648 }
2649 maxLength = std::max(length, maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002650 }
2651 }
2652
2653 return maxLength;
2654}
2655
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002656void Program::flagForDeletion()
2657{
2658 mDeleteStatus = true;
2659}
2660
2661bool Program::isFlaggedForDeletion() const
2662{
2663 return mDeleteStatus;
2664}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002665
2666void Program::validate()
2667{
2668 resetInfoLog();
2669
2670 if (!isLinked())
2671 {
2672 appendToInfoLog("Program has not been successfully linked.");
2673 mValidated = false;
2674 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002675 else
2676 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002677 applyUniforms();
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002678 if (!validateSamplers(true))
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002679 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002680 mValidated = false;
2681 }
2682 else
2683 {
2684 mValidated = true;
2685 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002686 }
2687}
2688
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002689bool Program::validateSamplers(bool logErrors)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002690{
2691 // if any two active samplers in a program are of different types, but refer to the same
2692 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2693 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002694
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002695 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002696 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2697
2698 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2699 {
2700 textureUnitType[i] = TEXTURE_UNKNOWN;
2701 }
2702
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00002703 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002704 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002705 if (mSamplersPS[i].active)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002706 {
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002707 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002708
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002709 if (unit >= maxCombinedTextureImageUnits)
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002710 {
2711 if (logErrors)
2712 {
2713 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
2714 }
2715
2716 return false;
2717 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002718
2719 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002720 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002721 if (mSamplersPS[i].textureType != textureUnitType[unit])
2722 {
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002723 if (logErrors)
2724 {
2725 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2726 }
2727
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002728 return false;
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002729 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002730 }
2731 else
2732 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002733 textureUnitType[unit] = mSamplersPS[i].textureType;
2734 }
2735 }
2736 }
2737
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00002738 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002739 {
2740 if (mSamplersVS[i].active)
2741 {
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002742 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002743
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002744 if (unit >= maxCombinedTextureImageUnits)
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002745 {
2746 if (logErrors)
2747 {
2748 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
2749 }
2750
2751 return false;
2752 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002753
2754 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2755 {
2756 if (mSamplersVS[i].textureType != textureUnitType[unit])
2757 {
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002758 if (logErrors)
2759 {
2760 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2761 }
2762
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002763 return false;
2764 }
2765 }
2766 else
2767 {
2768 textureUnitType[unit] = mSamplersVS[i].textureType;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002769 }
2770 }
2771 }
2772
2773 return true;
2774}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002775
daniel@transgaming.com31754962010-11-28 02:02:52 +00002776GLint Program::getDxDepthRangeLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002777{
daniel@transgaming.com31754962010-11-28 02:02:52 +00002778 return mDxDepthRangeLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002779}
2780
2781GLint Program::getDxDepthLocation() const
2782{
2783 return mDxDepthLocation;
2784}
2785
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00002786GLint Program::getDxCoordLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002787{
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00002788 return mDxCoordLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002789}
2790
2791GLint Program::getDxHalfPixelSizeLocation() const
2792{
2793 return mDxHalfPixelSizeLocation;
2794}
2795
2796GLint Program::getDxFrontCCWLocation() const
2797{
2798 return mDxFrontCCWLocation;
2799}
2800
2801GLint Program::getDxPointsOrLinesLocation() const
2802{
2803 return mDxPointsOrLinesLocation;
2804}
2805
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002806}