blob: b81c3cbc8b40010519976131257bef414911d76e [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;
1924
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001925 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001926 {
1927 return false;
1928 }
1929 else
1930 {
1931 return true;
1932 }
1933 }
1934
daniel@transgaming.comf5c8a2e2012-06-05 19:51:43 +00001935 if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constantDescription);
1936 if (shader == GL_VERTEX_SHADER) uniform->vs.set(constantDescription);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00001937
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001938 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001939 unsigned int uniformIndex = mUniforms.size() - 1;
1940
1941 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1942 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001943 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001944 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001945
1946 return true;
1947}
1948
apatrick@chromium.orge057c5d2012-01-26 19:18:24 +00001949Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, const std::string &_name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001950{
1951 if (constantDescription.Rows == 1) // Vectors and scalars
1952 {
1953 switch (constantDescription.Type)
1954 {
1955 case D3DXPT_SAMPLER2D:
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001956 switch (constantDescription.Columns)
1957 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001958 case 1: return new Uniform(GL_SAMPLER_2D, _name, constantDescription.Elements);
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001959 default: UNREACHABLE();
1960 }
1961 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001962 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001963 switch (constantDescription.Columns)
1964 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001965 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001966 default: UNREACHABLE();
1967 }
1968 break;
1969 case D3DXPT_BOOL:
1970 switch (constantDescription.Columns)
1971 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001972 case 1: return new Uniform(GL_BOOL, _name, constantDescription.Elements);
1973 case 2: return new Uniform(GL_BOOL_VEC2, _name, constantDescription.Elements);
1974 case 3: return new Uniform(GL_BOOL_VEC3, _name, constantDescription.Elements);
1975 case 4: return new Uniform(GL_BOOL_VEC4, _name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001976 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001977 }
1978 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001979 case D3DXPT_INT:
1980 switch (constantDescription.Columns)
1981 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001982 case 1: return new Uniform(GL_INT, _name, constantDescription.Elements);
1983 case 2: return new Uniform(GL_INT_VEC2, _name, constantDescription.Elements);
1984 case 3: return new Uniform(GL_INT_VEC3, _name, constantDescription.Elements);
1985 case 4: return new Uniform(GL_INT_VEC4, _name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001986 default: UNREACHABLE();
1987 }
1988 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001989 case D3DXPT_FLOAT:
1990 switch (constantDescription.Columns)
1991 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001992 case 1: return new Uniform(GL_FLOAT, _name, constantDescription.Elements);
1993 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constantDescription.Elements);
1994 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constantDescription.Elements);
1995 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001996 default: UNREACHABLE();
1997 }
1998 break;
1999 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002000 UNREACHABLE();
2001 }
2002 }
2003 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
2004 {
2005 switch (constantDescription.Type)
2006 {
2007 case D3DXPT_FLOAT:
2008 switch (constantDescription.Rows)
2009 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002010 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constantDescription.Elements);
2011 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constantDescription.Elements);
2012 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002013 default: UNREACHABLE();
2014 }
2015 break;
2016 default: UNREACHABLE();
2017 }
2018 }
2019 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00002020
2021 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002022}
2023
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002024// This method needs to match OutputHLSL::decorate
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002025std::string Program::decorateAttribute(const std::string &name)
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002026{
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002027 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002028 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002029 return "_" + name;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002030 }
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002031
2032 return name;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002033}
2034
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002035std::string Program::undecorateUniform(const std::string &_name)
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002036{
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002037 std::string name = _name;
2038
2039 // Remove any structure field decoration
2040 size_t pos = 0;
2041 while ((pos = name.find("._", pos)) != std::string::npos)
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002042 {
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002043 name.replace(pos, 2, ".");
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002044 }
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002045
2046 // Remove the leading decoration
2047 if (name[0] == '_')
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002048 {
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002049 return name.substr(1);
2050 }
2051 else if (name.compare(0, 3, "ar_") == 0)
2052 {
2053 return name.substr(3);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002054 }
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002055
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002056 return name;
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002057}
2058
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002059void Program::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002060{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002061 float vector[D3D9_MAX_FLOAT_CONSTANTS * 4];
2062 BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS];
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002063
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002064 if (targetUniform->ps.registerCount && targetUniform->ps.float4Index >= 0 ||
2065 targetUniform->vs.registerCount && targetUniform->vs.float4Index >= 0)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002066 {
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002067 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002068 for (int i = 0; i < count; i++)
2069 {
2070 for (int j = 0; j < 4; j++)
2071 {
2072 if (j < width)
2073 {
2074 vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f;
2075 }
2076 else
2077 {
2078 vector[i * 4 + j] = 0.0f;
2079 }
2080 }
2081 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002082 }
2083
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002084 if (targetUniform->ps.registerCount && targetUniform->ps.boolIndex >= 0 ||
2085 targetUniform->vs.registerCount && targetUniform->vs.boolIndex >= 0)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002086 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002087 int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0;
2088 int vsCount = targetUniform->vs.boolIndex >= 0 ? targetUniform->vs.registerCount : 0;
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002089 int copyCount = std::min(count * width, std::max(psCount, vsCount));
2090 ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS);
2091 for (int i = 0; i < copyCount; i++)
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002092 {
2093 boolVector[i] = v[i] != GL_FALSE;
2094 }
2095 }
2096
2097 if (targetUniform->ps.registerCount)
2098 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002099 if (targetUniform->ps.float4Index >= 0)
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002100 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002101 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002102 }
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002103
2104 if (targetUniform->ps.boolIndex >= 0)
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002105 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002106 mDevice->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002107 }
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002108 }
2109
2110 if (targetUniform->vs.registerCount)
2111 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002112 if (targetUniform->vs.float4Index >= 0)
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002113 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002114 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002115 }
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002116
2117 if (targetUniform->vs.boolIndex >= 0)
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002118 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002119 mDevice->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002120 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002121 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002122}
2123
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002124bool Program::applyUniformnfv(Uniform *targetUniform, const GLfloat *v)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002125{
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002126 if (targetUniform->ps.registerCount)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002127 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002128 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002129 }
2130
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002131 if (targetUniform->vs.registerCount)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002132 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002133 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002134 }
2135
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002136 return true;
2137}
2138
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002139bool Program::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002140{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002141 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2142 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002143
2144 for (int i = 0; i < count; i++)
2145 {
2146 vector[i] = D3DXVECTOR4((float)v[i], 0, 0, 0);
2147 }
2148
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002149 if (targetUniform->ps.registerCount)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002150 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002151 if (targetUniform->ps.samplerIndex >= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002152 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002153 unsigned int firstIndex = targetUniform->ps.samplerIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002154
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002155 for (int i = 0; i < count; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002156 {
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002157 unsigned int samplerIndex = firstIndex + i;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002158
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002159 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002160 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002161 ASSERT(mSamplersPS[samplerIndex].active);
2162 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002163 }
2164 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002165 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002166 else
2167 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002168 ASSERT(targetUniform->ps.float4Index >= 0);
2169 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount);
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002170 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002171 }
2172
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002173 if (targetUniform->vs.registerCount)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002174 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002175 if (targetUniform->vs.samplerIndex >= 0)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002176 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002177 unsigned int firstIndex = targetUniform->vs.samplerIndex;
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002178
2179 for (int i = 0; i < count; i++)
2180 {
2181 unsigned int samplerIndex = firstIndex + i;
2182
2183 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2184 {
2185 ASSERT(mSamplersVS[samplerIndex].active);
2186 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2187 }
2188 }
2189 }
2190 else
2191 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002192 ASSERT(targetUniform->vs.float4Index >= 0);
2193 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002194 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002195 }
2196
2197 return true;
2198}
2199
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002200bool Program::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002201{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002202 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2203 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002204
2205 for (int i = 0; i < count; i++)
2206 {
2207 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2208
2209 v += 2;
2210 }
2211
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002212 applyUniformniv(targetUniform, count, vector);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002213
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002214 return true;
2215}
2216
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002217bool Program::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002218{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002219 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2220 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002221
2222 for (int i = 0; i < count; i++)
2223 {
2224 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2225
2226 v += 3;
2227 }
2228
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002229 applyUniformniv(targetUniform, count, vector);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002230
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002231 return true;
2232}
2233
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002234bool Program::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002235{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002236 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2237 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002238
2239 for (int i = 0; i < count; i++)
2240 {
2241 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2242
2243 v += 4;
2244 }
2245
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002246 applyUniformniv(targetUniform, count, vector);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002247
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002248 return true;
2249}
2250
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002251void Program::applyUniformniv(Uniform *targetUniform, GLsizei count, const D3DXVECTOR4 *vector)
2252{
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002253 if (targetUniform->ps.registerCount)
2254 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002255 ASSERT(targetUniform->ps.float4Index >= 0);
2256 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002257 }
2258
2259 if (targetUniform->vs.registerCount)
2260 {
daniel@transgaming.comea7c3452012-06-05 19:51:40 +00002261 ASSERT(targetUniform->vs.float4Index >= 0);
2262 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002263 }
2264}
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002265
2266// append a santized message to the program info log.
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002267// The D3D compiler includes a fake file path in some of the warning or error
2268// messages, so lets remove all occurrences of this fake file path from the log.
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002269void Program::appendToInfoLogSanitized(const char *message)
2270{
2271 std::string msg(message);
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002272
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002273 size_t found;
2274 do
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002275 {
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002276 found = msg.find(fakepath);
2277 if (found != std::string::npos)
2278 {
2279 msg.erase(found, strlen(fakepath));
2280 }
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002281 }
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002282 while (found != std::string::npos);
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002283
2284 appendToInfoLog("%s\n", msg.c_str());
2285}
2286
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002287void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002288{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002289 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002290 {
2291 return;
2292 }
2293
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002294 char info[1024];
2295
2296 va_list vararg;
2297 va_start(vararg, format);
2298 vsnprintf(info, sizeof(info), format, vararg);
2299 va_end(vararg);
2300
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002301 size_t infoLength = strlen(info);
2302
2303 if (!mInfoLog)
2304 {
2305 mInfoLog = new char[infoLength + 1];
2306 strcpy(mInfoLog, info);
2307 }
2308 else
2309 {
2310 size_t logLength = strlen(mInfoLog);
2311 char *newLog = new char[logLength + infoLength + 1];
2312 strcpy(newLog, mInfoLog);
2313 strcpy(newLog + logLength, info);
2314
2315 delete[] mInfoLog;
2316 mInfoLog = newLog;
2317 }
2318}
2319
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002320void Program::resetInfoLog()
2321{
2322 if (mInfoLog)
2323 {
2324 delete [] mInfoLog;
daniel@transgaming.com6a20d102010-08-31 13:54:27 +00002325 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002326 }
2327}
2328
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +00002329// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002330void Program::unlink(bool destroy)
2331{
2332 if (destroy) // Object being destructed
2333 {
2334 if (mFragmentShader)
2335 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002336 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002337 mFragmentShader = NULL;
2338 }
2339
2340 if (mVertexShader)
2341 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002342 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002343 mVertexShader = NULL;
2344 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002345 }
2346
2347 if (mPixelExecutable)
2348 {
2349 mPixelExecutable->Release();
2350 mPixelExecutable = NULL;
2351 }
2352
2353 if (mVertexExecutable)
2354 {
2355 mVertexExecutable->Release();
2356 mVertexExecutable = NULL;
2357 }
2358
2359 if (mConstantTablePS)
2360 {
2361 mConstantTablePS->Release();
2362 mConstantTablePS = NULL;
2363 }
2364
2365 if (mConstantTableVS)
2366 {
2367 mConstantTableVS->Release();
2368 mConstantTableVS = NULL;
2369 }
2370
2371 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2372 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002373 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002374 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002375 }
2376
2377 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2378 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002379 mSamplersPS[index].active = false;
2380 }
2381
2382 for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
2383 {
2384 mSamplersVS[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002385 }
2386
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00002387 mUsedVertexSamplerRange = 0;
2388 mUsedPixelSamplerRange = 0;
2389
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002390 while (!mUniforms.empty())
2391 {
2392 delete mUniforms.back();
2393 mUniforms.pop_back();
2394 }
2395
daniel@transgaming.com31754962010-11-28 02:02:52 +00002396 mDxDepthRangeLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002397 mDxDepthLocation = -1;
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00002398 mDxCoordLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002399 mDxHalfPixelSizeLocation = -1;
2400 mDxFrontCCWLocation = -1;
2401 mDxPointsOrLinesLocation = -1;
2402
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002403 mUniformIndex.clear();
2404
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002405 mPixelHLSL.clear();
2406 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002407
2408 delete[] mInfoLog;
2409 mInfoLog = NULL;
2410
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002411 mLinked = false;
2412}
2413
2414bool Program::isLinked()
2415{
2416 return mLinked;
2417}
2418
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002419bool Program::isValidated() const
2420{
2421 return mValidated;
2422}
2423
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002424void Program::release()
2425{
2426 mRefCount--;
2427
2428 if (mRefCount == 0 && mDeleteStatus)
2429 {
2430 mResourceManager->deleteProgram(mHandle);
2431 }
2432}
2433
2434void Program::addRef()
2435{
2436 mRefCount++;
2437}
2438
2439unsigned int Program::getRefCount() const
2440{
2441 return mRefCount;
2442}
2443
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002444unsigned int Program::getSerial() const
2445{
2446 return mSerial;
2447}
2448
2449unsigned int Program::issueSerial()
2450{
2451 return mCurrentSerial++;
2452}
2453
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002454int Program::getInfoLogLength() const
2455{
2456 if (!mInfoLog)
2457 {
2458 return 0;
2459 }
2460 else
2461 {
2462 return strlen(mInfoLog) + 1;
2463 }
2464}
2465
2466void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2467{
2468 int index = 0;
2469
daniel@transgaming.com807d8c32012-04-04 15:06:04 +00002470 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002471 {
daniel@transgaming.com807d8c32012-04-04 15:06:04 +00002472 if (mInfoLog)
2473 {
2474 index = std::min(bufSize - 1, (int)strlen(mInfoLog));
2475 memcpy(infoLog, mInfoLog, index);
2476 }
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002477
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002478 infoLog[index] = '\0';
2479 }
2480
2481 if (length)
2482 {
2483 *length = index;
2484 }
2485}
2486
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002487void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2488{
2489 int total = 0;
2490
2491 if (mVertexShader)
2492 {
2493 if (total < maxCount)
2494 {
2495 shaders[total] = mVertexShader->getHandle();
2496 }
2497
2498 total++;
2499 }
2500
2501 if (mFragmentShader)
2502 {
2503 if (total < maxCount)
2504 {
2505 shaders[total] = mFragmentShader->getHandle();
2506 }
2507
2508 total++;
2509 }
2510
2511 if (count)
2512 {
2513 *count = total;
2514 }
2515}
2516
daniel@transgaming.com85423182010-04-22 13:35:27 +00002517void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2518{
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002519 // Skip over inactive attributes
2520 unsigned int activeAttribute = 0;
2521 unsigned int attribute;
2522 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
daniel@transgaming.com85423182010-04-22 13:35:27 +00002523 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002524 if (mLinkedAttribute[attribute].name.empty())
daniel@transgaming.com85423182010-04-22 13:35:27 +00002525 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002526 continue;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002527 }
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002528
2529 if (activeAttribute == index)
2530 {
2531 break;
2532 }
2533
2534 activeAttribute++;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002535 }
2536
2537 if (bufsize > 0)
2538 {
2539 const char *string = mLinkedAttribute[attribute].name.c_str();
2540
2541 strncpy(name, string, bufsize);
2542 name[bufsize - 1] = '\0';
2543
2544 if (length)
2545 {
2546 *length = strlen(name);
2547 }
2548 }
2549
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002550 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002551
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002552 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002553}
2554
2555GLint Program::getActiveAttributeCount()
2556{
2557 int count = 0;
2558
2559 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2560 {
2561 if (!mLinkedAttribute[attributeIndex].name.empty())
2562 {
2563 count++;
2564 }
2565 }
2566
2567 return count;
2568}
2569
2570GLint Program::getActiveAttributeMaxLength()
2571{
2572 int maxLength = 0;
2573
2574 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2575 {
2576 if (!mLinkedAttribute[attributeIndex].name.empty())
2577 {
2578 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2579 }
2580 }
2581
2582 return maxLength;
2583}
2584
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002585void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2586{
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002587 // Skip over internal uniforms
2588 unsigned int activeUniform = 0;
2589 unsigned int uniform;
2590 for (uniform = 0; uniform < mUniforms.size(); uniform++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002591 {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002592 if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002593 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002594 continue;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002595 }
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002596
2597 if (activeUniform == index)
2598 {
2599 break;
2600 }
2601
2602 activeUniform++;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002603 }
2604
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002605 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2606
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002607 if (bufsize > 0)
2608 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002609 std::string string = mUniforms[uniform]->name;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002610
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002611 if (mUniforms[uniform]->isArray())
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002612 {
2613 string += "[0]";
2614 }
2615
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002616 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002617 name[bufsize - 1] = '\0';
2618
2619 if (length)
2620 {
2621 *length = strlen(name);
2622 }
2623 }
2624
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002625 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002626
2627 *type = mUniforms[uniform]->type;
2628}
2629
2630GLint Program::getActiveUniformCount()
2631{
2632 int count = 0;
2633
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002634 unsigned int numUniforms = mUniforms.size();
2635 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002636 {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002637 if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002638 {
2639 count++;
2640 }
2641 }
2642
2643 return count;
2644}
2645
2646GLint Program::getActiveUniformMaxLength()
2647{
2648 int maxLength = 0;
2649
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002650 unsigned int numUniforms = mUniforms.size();
2651 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002652 {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002653 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002654 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002655 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2656 if (mUniforms[uniformIndex]->isArray())
zmo@google.com53d73e02011-03-24 21:27:57 +00002657 {
2658 length += 3; // Counting in "[0]".
2659 }
2660 maxLength = std::max(length, maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002661 }
2662 }
2663
2664 return maxLength;
2665}
2666
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002667void Program::flagForDeletion()
2668{
2669 mDeleteStatus = true;
2670}
2671
2672bool Program::isFlaggedForDeletion() const
2673{
2674 return mDeleteStatus;
2675}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002676
2677void Program::validate()
2678{
2679 resetInfoLog();
2680
2681 if (!isLinked())
2682 {
2683 appendToInfoLog("Program has not been successfully linked.");
2684 mValidated = false;
2685 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002686 else
2687 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002688 applyUniforms();
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002689 if (!validateSamplers(true))
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002690 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002691 mValidated = false;
2692 }
2693 else
2694 {
2695 mValidated = true;
2696 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002697 }
2698}
2699
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002700bool Program::validateSamplers(bool logErrors)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002701{
2702 // if any two active samplers in a program are of different types, but refer to the same
2703 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2704 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002705
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002706 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002707 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2708
2709 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2710 {
2711 textureUnitType[i] = TEXTURE_UNKNOWN;
2712 }
2713
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00002714 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002715 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002716 if (mSamplersPS[i].active)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002717 {
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002718 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002719
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002720 if (unit >= maxCombinedTextureImageUnits)
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002721 {
2722 if (logErrors)
2723 {
2724 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
2725 }
2726
2727 return false;
2728 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002729
2730 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002731 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002732 if (mSamplersPS[i].textureType != textureUnitType[unit])
2733 {
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002734 if (logErrors)
2735 {
2736 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2737 }
2738
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002739 return false;
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002740 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002741 }
2742 else
2743 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002744 textureUnitType[unit] = mSamplersPS[i].textureType;
2745 }
2746 }
2747 }
2748
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00002749 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002750 {
2751 if (mSamplersVS[i].active)
2752 {
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002753 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002754
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002755 if (unit >= maxCombinedTextureImageUnits)
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002756 {
2757 if (logErrors)
2758 {
2759 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
2760 }
2761
2762 return false;
2763 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002764
2765 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2766 {
2767 if (mSamplersVS[i].textureType != textureUnitType[unit])
2768 {
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002769 if (logErrors)
2770 {
2771 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2772 }
2773
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002774 return false;
2775 }
2776 }
2777 else
2778 {
2779 textureUnitType[unit] = mSamplersVS[i].textureType;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002780 }
2781 }
2782 }
2783
2784 return true;
2785}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002786
daniel@transgaming.com31754962010-11-28 02:02:52 +00002787GLint Program::getDxDepthRangeLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002788{
daniel@transgaming.com31754962010-11-28 02:02:52 +00002789 return mDxDepthRangeLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002790}
2791
2792GLint Program::getDxDepthLocation() const
2793{
2794 return mDxDepthLocation;
2795}
2796
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00002797GLint Program::getDxCoordLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002798{
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00002799 return mDxCoordLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002800}
2801
2802GLint Program::getDxHalfPixelSizeLocation() const
2803{
2804 return mDxHalfPixelSizeLocation;
2805}
2806
2807GLint Program::getDxFrontCCWLocation() const
2808{
2809 return mDxFrontCCWLocation;
2810}
2811
2812GLint Program::getDxPointsOrLinesLocation() const
2813{
2814 return mDxPointsOrLinesLocation;
2815}
2816
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002817}