blob: 0e48a9f6dcf53bd659f9f7036493c85950d5f310 [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.com86487c22010-03-11 19:41:43 +00001688 if (!linkUniforms(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.com86487c22010-03-11 19:41:43 +00001693 if (!linkUniforms(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.com86487c22010-03-11 19:41:43 +00001797bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1798{
1799 D3DXCONSTANTTABLE_DESC constantTableDescription;
1800 D3DXCONSTANT_DESC constantDescription;
1801 UINT descriptionCount = 1;
1802
1803 constantTable->GetDesc(&constantTableDescription);
1804
1805 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1806 {
1807 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001808 HRESULT result = constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1809 ASSERT(SUCCEEDED(result));
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001810
1811 if (!defineUniform(constantHandle, constantDescription))
1812 {
1813 return false;
1814 }
1815 }
1816
1817 return true;
1818}
1819
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001820// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001821// Returns true if succesful (uniform not already defined)
1822bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1823{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001824 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1825 {
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001826 for (unsigned int i = 0; i < constantDescription.RegisterCount; i++)
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001827 {
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001828 D3DXHANDLE psConstant = mConstantTablePS->GetConstantByName(NULL, constantDescription.Name);
1829 D3DXHANDLE vsConstant = mConstantTableVS->GetConstantByName(NULL, constantDescription.Name);
1830
1831 if (psConstant)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001832 {
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001833 unsigned int samplerIndex = mConstantTablePS->GetSamplerIndex(psConstant) + i;
1834
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001835 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1836 {
1837 mSamplersPS[samplerIndex].active = true;
1838 mSamplersPS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1839 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00001840 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001841 }
1842 else
1843 {
1844 appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
1845 return false;
1846 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001847 }
1848
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001849 if (vsConstant)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001850 {
daniel@transgaming.comc3336992011-11-14 21:15:45 +00001851 unsigned int samplerIndex = mConstantTableVS->GetSamplerIndex(vsConstant) + i;
1852
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001853 if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
1854 {
1855 mSamplersVS[samplerIndex].active = true;
1856 mSamplersVS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1857 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00001858 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
daniel@transgaming.com424bb492011-05-11 15:36:59 +00001859 }
1860 else
1861 {
1862 appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
1863 return false;
1864 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001865 }
daniel@transgaming.com41b2fbd2010-12-13 18:27:12 +00001866 }
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001867 }
1868
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001869 switch(constantDescription.Class)
1870 {
1871 case D3DXPC_STRUCT:
1872 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001873 for (unsigned int arrayIndex = 0; arrayIndex < constantDescription.Elements; arrayIndex++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001874 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001875 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001876 {
daniel@transgaming.comce864422010-11-18 13:16:49 +00001877 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1878
1879 D3DXCONSTANT_DESC fieldDescription;
1880 UINT descriptionCount = 1;
1881
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00001882 HRESULT result = mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1883 ASSERT(SUCCEEDED(result));
daniel@transgaming.comce864422010-11-18 13:16:49 +00001884
1885 std::string structIndex = (constantDescription.Elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
1886
1887 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + structIndex + "."))
1888 {
1889 return false;
1890 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001891 }
1892 }
1893
1894 return true;
1895 }
1896 case D3DXPC_SCALAR:
1897 case D3DXPC_VECTOR:
1898 case D3DXPC_MATRIX_COLUMNS:
1899 case D3DXPC_OBJECT:
1900 return defineUniform(constantDescription, name + constantDescription.Name);
1901 default:
1902 UNREACHABLE();
1903 return false;
1904 }
1905}
1906
apatrick@chromium.orge057c5d2012-01-26 19:18:24 +00001907bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, const std::string &_name)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001908{
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001909 Uniform *uniform = createUniform(constantDescription, _name);
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001910
1911 if(!uniform)
1912 {
1913 return false;
1914 }
1915
1916 // Check if already defined
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001917 GLint location = getUniformLocation(uniform->name);
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001918 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001919
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001920 if (location >= 0)
1921 {
1922 delete uniform;
1923
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001924 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001925 {
1926 return false;
1927 }
1928 else
1929 {
1930 return true;
1931 }
1932 }
1933
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00001934 initializeConstantHandles(uniform, &uniform->ps, mConstantTablePS);
1935 initializeConstantHandles(uniform, &uniform->vs, mConstantTableVS);
1936
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001937 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001938 unsigned int uniformIndex = mUniforms.size() - 1;
1939
1940 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1941 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001942 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001943 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001944
1945 return true;
1946}
1947
apatrick@chromium.orge057c5d2012-01-26 19:18:24 +00001948Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, const std::string &_name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001949{
1950 if (constantDescription.Rows == 1) // Vectors and scalars
1951 {
1952 switch (constantDescription.Type)
1953 {
1954 case D3DXPT_SAMPLER2D:
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001955 switch (constantDescription.Columns)
1956 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001957 case 1: return new Uniform(GL_SAMPLER_2D, _name, constantDescription.Elements);
daniel@transgaming.coma9cd70a2010-09-15 15:48:57 +00001958 default: UNREACHABLE();
1959 }
1960 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001961 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001962 switch (constantDescription.Columns)
1963 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001964 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001965 default: UNREACHABLE();
1966 }
1967 break;
1968 case D3DXPT_BOOL:
1969 switch (constantDescription.Columns)
1970 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001971 case 1: return new Uniform(GL_BOOL, _name, constantDescription.Elements);
1972 case 2: return new Uniform(GL_BOOL_VEC2, _name, constantDescription.Elements);
1973 case 3: return new Uniform(GL_BOOL_VEC3, _name, constantDescription.Elements);
1974 case 4: return new Uniform(GL_BOOL_VEC4, _name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001975 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001976 }
1977 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001978 case D3DXPT_INT:
1979 switch (constantDescription.Columns)
1980 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001981 case 1: return new Uniform(GL_INT, _name, constantDescription.Elements);
1982 case 2: return new Uniform(GL_INT_VEC2, _name, constantDescription.Elements);
1983 case 3: return new Uniform(GL_INT_VEC3, _name, constantDescription.Elements);
1984 case 4: return new Uniform(GL_INT_VEC4, _name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001985 default: UNREACHABLE();
1986 }
1987 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001988 case D3DXPT_FLOAT:
1989 switch (constantDescription.Columns)
1990 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00001991 case 1: return new Uniform(GL_FLOAT, _name, constantDescription.Elements);
1992 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constantDescription.Elements);
1993 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constantDescription.Elements);
1994 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001995 default: UNREACHABLE();
1996 }
1997 break;
1998 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001999 UNREACHABLE();
2000 }
2001 }
2002 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
2003 {
2004 switch (constantDescription.Type)
2005 {
2006 case D3DXPT_FLOAT:
2007 switch (constantDescription.Rows)
2008 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002009 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constantDescription.Elements);
2010 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constantDescription.Elements);
2011 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002012 default: UNREACHABLE();
2013 }
2014 break;
2015 default: UNREACHABLE();
2016 }
2017 }
2018 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00002019
2020 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002021}
2022
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002023// This method needs to match OutputHLSL::decorate
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002024std::string Program::decorateAttribute(const std::string &name)
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002025{
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002026 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002027 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002028 return "_" + name;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002029 }
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002030
2031 return name;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002032}
2033
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002034std::string Program::undecorateUniform(const std::string &_name)
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002035{
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002036 std::string name = _name;
2037
2038 // Remove any structure field decoration
2039 size_t pos = 0;
2040 while ((pos = name.find("._", pos)) != std::string::npos)
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002041 {
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002042 name.replace(pos, 2, ".");
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002043 }
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002044
2045 // Remove the leading decoration
2046 if (name[0] == '_')
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002047 {
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002048 return name.substr(1);
2049 }
2050 else if (name.compare(0, 3, "ar_") == 0)
2051 {
2052 return name.substr(3);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002053 }
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002054
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002055 return name;
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002056}
2057
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002058void Program::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002059{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002060 float vector[D3D9_MAX_FLOAT_CONSTANTS * 4];
2061 BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS];
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002062
2063 if (targetUniform->ps.registerCount && targetUniform->ps.registerSet == D3DXRS_FLOAT4 ||
2064 targetUniform->vs.registerCount && targetUniform->vs.registerSet == D3DXRS_FLOAT4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002065 {
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002066 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002067 for (int i = 0; i < count; i++)
2068 {
2069 for (int j = 0; j < 4; j++)
2070 {
2071 if (j < width)
2072 {
2073 vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f;
2074 }
2075 else
2076 {
2077 vector[i * 4 + j] = 0.0f;
2078 }
2079 }
2080 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002081 }
2082
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002083 if (targetUniform->ps.registerCount && targetUniform->ps.registerSet == D3DXRS_BOOL ||
2084 targetUniform->vs.registerCount && targetUniform->vs.registerSet == D3DXRS_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002085 {
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002086 int psCount = targetUniform->ps.registerSet == D3DXRS_BOOL ? targetUniform->ps.registerCount : 0;
2087 int vsCount = targetUniform->vs.registerSet == D3DXRS_BOOL ? targetUniform->vs.registerCount : 0;
2088 int copyCount = std::min(count * width, std::max(psCount, vsCount));
2089 ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS);
2090 for (int i = 0; i < copyCount; i++)
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002091 {
2092 boolVector[i] = v[i] != GL_FALSE;
2093 }
2094 }
2095
2096 if (targetUniform->ps.registerCount)
2097 {
2098 if (targetUniform->ps.registerSet == D3DXRS_FLOAT4)
2099 {
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +00002100 mDevice->SetPixelShaderConstantF(targetUniform->ps.registerIndex, vector, targetUniform->ps.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002101 }
2102 else if (targetUniform->ps.registerSet == D3DXRS_BOOL)
2103 {
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +00002104 mDevice->SetPixelShaderConstantB(targetUniform->ps.registerIndex, boolVector, targetUniform->ps.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002105 }
2106 else UNREACHABLE();
2107 }
2108
2109 if (targetUniform->vs.registerCount)
2110 {
2111 if (targetUniform->vs.registerSet == D3DXRS_FLOAT4)
2112 {
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +00002113 mDevice->SetVertexShaderConstantF(targetUniform->vs.registerIndex, vector, targetUniform->vs.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002114 }
2115 else if (targetUniform->vs.registerSet == D3DXRS_BOOL)
2116 {
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +00002117 mDevice->SetVertexShaderConstantB(targetUniform->vs.registerIndex, boolVector, targetUniform->vs.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002118 }
2119 else UNREACHABLE();
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002120 }
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002121}
2122
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002123bool Program::applyUniformnfv(Uniform *targetUniform, const GLfloat *v)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002124{
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002125 if (targetUniform->ps.registerCount)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002126 {
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +00002127 mDevice->SetPixelShaderConstantF(targetUniform->ps.registerIndex, v, targetUniform->ps.registerCount);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002128 }
2129
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002130 if (targetUniform->vs.registerCount)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002131 {
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +00002132 mDevice->SetVertexShaderConstantF(targetUniform->vs.registerIndex, v, targetUniform->vs.registerCount);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00002133 }
2134
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002135 return true;
2136}
2137
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002138bool Program::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002139{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002140 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2141 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002142
2143 for (int i = 0; i < count; i++)
2144 {
2145 vector[i] = D3DXVECTOR4((float)v[i], 0, 0, 0);
2146 }
2147
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002148 if (targetUniform->ps.registerCount)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002149 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002150 if (targetUniform->ps.registerSet == D3DXRS_SAMPLER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002151 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002152 unsigned int firstIndex = targetUniform->ps.registerIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002153
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002154 for (int i = 0; i < count; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002155 {
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002156 unsigned int samplerIndex = firstIndex + i;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00002157
daniel@transgaming.coma41e6e32010-12-15 15:45:30 +00002158 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002159 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002160 ASSERT(mSamplersPS[samplerIndex].active);
2161 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002162 }
2163 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002164 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002165 else
2166 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002167 ASSERT(targetUniform->ps.registerSet == D3DXRS_FLOAT4);
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +00002168 mDevice->SetPixelShaderConstantF(targetUniform->ps.registerIndex, (const float*)vector, targetUniform->ps.registerCount);
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002169 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002170 }
2171
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002172 if (targetUniform->vs.registerCount)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002173 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002174 if (targetUniform->vs.registerSet == D3DXRS_SAMPLER)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002175 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002176 unsigned int firstIndex = targetUniform->vs.registerIndex;
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002177
2178 for (int i = 0; i < count; i++)
2179 {
2180 unsigned int samplerIndex = firstIndex + i;
2181
2182 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2183 {
2184 ASSERT(mSamplersVS[samplerIndex].active);
2185 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2186 }
2187 }
2188 }
2189 else
2190 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002191 ASSERT(targetUniform->vs.registerSet == D3DXRS_FLOAT4);
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +00002192 mDevice->SetVertexShaderConstantF(targetUniform->vs.registerIndex, (const float *)vector, targetUniform->vs.registerCount);
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002193 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002194 }
2195
2196 return true;
2197}
2198
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002199bool Program::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002200{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002201 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2202 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002203
2204 for (int i = 0; i < count; i++)
2205 {
2206 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2207
2208 v += 2;
2209 }
2210
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002211 applyUniformniv(targetUniform, count, vector);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002212
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002213 return true;
2214}
2215
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002216bool Program::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002217{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002218 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2219 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002220
2221 for (int i = 0; i < count; i++)
2222 {
2223 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2224
2225 v += 3;
2226 }
2227
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002228 applyUniformniv(targetUniform, count, vector);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002229
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002230 return true;
2231}
2232
jbauman@chromium.orga28233e2011-10-12 16:51:33 +00002233bool Program::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002234{
jbauman@chromium.orge0f059c2012-01-24 23:21:52 +00002235 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2236 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002237
2238 for (int i = 0; i < count; i++)
2239 {
2240 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2241
2242 v += 4;
2243 }
2244
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002245 applyUniformniv(targetUniform, count, vector);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002246
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00002247 return true;
2248}
2249
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002250void Program::applyUniformniv(Uniform *targetUniform, GLsizei count, const D3DXVECTOR4 *vector)
2251{
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002252 if (targetUniform->ps.registerCount)
2253 {
2254 ASSERT(targetUniform->ps.registerSet == D3DXRS_FLOAT4);
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +00002255 mDevice->SetPixelShaderConstantF(targetUniform->ps.registerIndex, (const float *)vector, targetUniform->ps.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002256 }
2257
2258 if (targetUniform->vs.registerCount)
2259 {
2260 ASSERT(targetUniform->vs.registerSet == D3DXRS_FLOAT4);
daniel@transgaming.com96a4a6c2011-10-26 02:33:46 +00002261 mDevice->SetVertexShaderConstantF(targetUniform->vs.registerIndex, (const float *)vector, targetUniform->vs.registerCount);
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002262 }
2263}
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002264
2265// append a santized message to the program info log.
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002266// The D3D compiler includes a fake file path in some of the warning or error
2267// messages, so lets remove all occurrences of this fake file path from the log.
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002268void Program::appendToInfoLogSanitized(const char *message)
2269{
2270 std::string msg(message);
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002271
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002272 size_t found;
2273 do
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002274 {
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002275 found = msg.find(fakepath);
2276 if (found != std::string::npos)
2277 {
2278 msg.erase(found, strlen(fakepath));
2279 }
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002280 }
daniel@transgaming.com8a4dad62011-09-13 00:54:40 +00002281 while (found != std::string::npos);
daniel@transgaming.com87891f72011-06-01 15:28:35 +00002282
2283 appendToInfoLog("%s\n", msg.c_str());
2284}
2285
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002286void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002287{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002288 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002289 {
2290 return;
2291 }
2292
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002293 char info[1024];
2294
2295 va_list vararg;
2296 va_start(vararg, format);
2297 vsnprintf(info, sizeof(info), format, vararg);
2298 va_end(vararg);
2299
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002300 size_t infoLength = strlen(info);
2301
2302 if (!mInfoLog)
2303 {
2304 mInfoLog = new char[infoLength + 1];
2305 strcpy(mInfoLog, info);
2306 }
2307 else
2308 {
2309 size_t logLength = strlen(mInfoLog);
2310 char *newLog = new char[logLength + infoLength + 1];
2311 strcpy(newLog, mInfoLog);
2312 strcpy(newLog + logLength, info);
2313
2314 delete[] mInfoLog;
2315 mInfoLog = newLog;
2316 }
2317}
2318
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002319void Program::resetInfoLog()
2320{
2321 if (mInfoLog)
2322 {
2323 delete [] mInfoLog;
daniel@transgaming.com6a20d102010-08-31 13:54:27 +00002324 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002325 }
2326}
2327
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +00002328// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002329void Program::unlink(bool destroy)
2330{
2331 if (destroy) // Object being destructed
2332 {
2333 if (mFragmentShader)
2334 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002335 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002336 mFragmentShader = NULL;
2337 }
2338
2339 if (mVertexShader)
2340 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002341 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002342 mVertexShader = NULL;
2343 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002344 }
2345
2346 if (mPixelExecutable)
2347 {
2348 mPixelExecutable->Release();
2349 mPixelExecutable = NULL;
2350 }
2351
2352 if (mVertexExecutable)
2353 {
2354 mVertexExecutable->Release();
2355 mVertexExecutable = NULL;
2356 }
2357
2358 if (mConstantTablePS)
2359 {
2360 mConstantTablePS->Release();
2361 mConstantTablePS = NULL;
2362 }
2363
2364 if (mConstantTableVS)
2365 {
2366 mConstantTableVS->Release();
2367 mConstantTableVS = NULL;
2368 }
2369
2370 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2371 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00002372 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00002373 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002374 }
2375
2376 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2377 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002378 mSamplersPS[index].active = false;
2379 }
2380
2381 for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
2382 {
2383 mSamplersVS[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002384 }
2385
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00002386 mUsedVertexSamplerRange = 0;
2387 mUsedPixelSamplerRange = 0;
2388
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002389 while (!mUniforms.empty())
2390 {
2391 delete mUniforms.back();
2392 mUniforms.pop_back();
2393 }
2394
daniel@transgaming.com31754962010-11-28 02:02:52 +00002395 mDxDepthRangeLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002396 mDxDepthLocation = -1;
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00002397 mDxCoordLocation = -1;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002398 mDxHalfPixelSizeLocation = -1;
2399 mDxFrontCCWLocation = -1;
2400 mDxPointsOrLinesLocation = -1;
2401
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002402 mUniformIndex.clear();
2403
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00002404 mPixelHLSL.clear();
2405 mVertexHLSL.clear();
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002406
2407 delete[] mInfoLog;
2408 mInfoLog = NULL;
2409
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002410 mLinked = false;
2411}
2412
2413bool Program::isLinked()
2414{
2415 return mLinked;
2416}
2417
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002418bool Program::isValidated() const
2419{
2420 return mValidated;
2421}
2422
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00002423void Program::release()
2424{
2425 mRefCount--;
2426
2427 if (mRefCount == 0 && mDeleteStatus)
2428 {
2429 mResourceManager->deleteProgram(mHandle);
2430 }
2431}
2432
2433void Program::addRef()
2434{
2435 mRefCount++;
2436}
2437
2438unsigned int Program::getRefCount() const
2439{
2440 return mRefCount;
2441}
2442
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002443unsigned int Program::getSerial() const
2444{
2445 return mSerial;
2446}
2447
2448unsigned int Program::issueSerial()
2449{
2450 return mCurrentSerial++;
2451}
2452
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002453int Program::getInfoLogLength() const
2454{
2455 if (!mInfoLog)
2456 {
2457 return 0;
2458 }
2459 else
2460 {
2461 return strlen(mInfoLog) + 1;
2462 }
2463}
2464
2465void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2466{
2467 int index = 0;
2468
daniel@transgaming.com807d8c32012-04-04 15:06:04 +00002469 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002470 {
daniel@transgaming.com807d8c32012-04-04 15:06:04 +00002471 if (mInfoLog)
2472 {
2473 index = std::min(bufSize - 1, (int)strlen(mInfoLog));
2474 memcpy(infoLog, mInfoLog, index);
2475 }
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002476
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002477 infoLog[index] = '\0';
2478 }
2479
2480 if (length)
2481 {
2482 *length = index;
2483 }
2484}
2485
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002486void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2487{
2488 int total = 0;
2489
2490 if (mVertexShader)
2491 {
2492 if (total < maxCount)
2493 {
2494 shaders[total] = mVertexShader->getHandle();
2495 }
2496
2497 total++;
2498 }
2499
2500 if (mFragmentShader)
2501 {
2502 if (total < maxCount)
2503 {
2504 shaders[total] = mFragmentShader->getHandle();
2505 }
2506
2507 total++;
2508 }
2509
2510 if (count)
2511 {
2512 *count = total;
2513 }
2514}
2515
daniel@transgaming.com85423182010-04-22 13:35:27 +00002516void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2517{
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002518 // Skip over inactive attributes
2519 unsigned int activeAttribute = 0;
2520 unsigned int attribute;
2521 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
daniel@transgaming.com85423182010-04-22 13:35:27 +00002522 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002523 if (mLinkedAttribute[attribute].name.empty())
daniel@transgaming.com85423182010-04-22 13:35:27 +00002524 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002525 continue;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002526 }
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002527
2528 if (activeAttribute == index)
2529 {
2530 break;
2531 }
2532
2533 activeAttribute++;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002534 }
2535
2536 if (bufsize > 0)
2537 {
2538 const char *string = mLinkedAttribute[attribute].name.c_str();
2539
2540 strncpy(name, string, bufsize);
2541 name[bufsize - 1] = '\0';
2542
2543 if (length)
2544 {
2545 *length = strlen(name);
2546 }
2547 }
2548
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002549 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002550
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002551 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002552}
2553
2554GLint Program::getActiveAttributeCount()
2555{
2556 int count = 0;
2557
2558 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2559 {
2560 if (!mLinkedAttribute[attributeIndex].name.empty())
2561 {
2562 count++;
2563 }
2564 }
2565
2566 return count;
2567}
2568
2569GLint Program::getActiveAttributeMaxLength()
2570{
2571 int maxLength = 0;
2572
2573 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2574 {
2575 if (!mLinkedAttribute[attributeIndex].name.empty())
2576 {
2577 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2578 }
2579 }
2580
2581 return maxLength;
2582}
2583
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002584void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2585{
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002586 // Skip over internal uniforms
2587 unsigned int activeUniform = 0;
2588 unsigned int uniform;
2589 for (uniform = 0; uniform < mUniforms.size(); uniform++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002590 {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002591 if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002592 {
daniel@transgaming.comeea70792010-12-15 15:44:59 +00002593 continue;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002594 }
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002595
2596 if (activeUniform == index)
2597 {
2598 break;
2599 }
2600
2601 activeUniform++;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002602 }
2603
daniel@transgaming.com996675c2010-11-17 13:06:29 +00002604 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2605
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002606 if (bufsize > 0)
2607 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002608 std::string string = mUniforms[uniform]->name;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002609
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002610 if (mUniforms[uniform]->isArray())
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002611 {
2612 string += "[0]";
2613 }
2614
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002615 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002616 name[bufsize - 1] = '\0';
2617
2618 if (length)
2619 {
2620 *length = strlen(name);
2621 }
2622 }
2623
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002624 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002625
2626 *type = mUniforms[uniform]->type;
2627}
2628
2629GLint Program::getActiveUniformCount()
2630{
2631 int count = 0;
2632
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002633 unsigned int numUniforms = mUniforms.size();
2634 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002635 {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002636 if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002637 {
2638 count++;
2639 }
2640 }
2641
2642 return count;
2643}
2644
2645GLint Program::getActiveUniformMaxLength()
2646{
2647 int maxLength = 0;
2648
daniel@transgaming.comd08ea902010-05-14 19:41:36 +00002649 unsigned int numUniforms = mUniforms.size();
2650 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002651 {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002652 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002653 {
daniel@transgaming.com024f1a92011-09-20 16:06:25 +00002654 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2655 if (mUniforms[uniformIndex]->isArray())
zmo@google.com53d73e02011-03-24 21:27:57 +00002656 {
2657 length += 3; // Counting in "[0]".
2658 }
2659 maxLength = std::max(length, maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002660 }
2661 }
2662
2663 return maxLength;
2664}
2665
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002666void Program::flagForDeletion()
2667{
2668 mDeleteStatus = true;
2669}
2670
2671bool Program::isFlaggedForDeletion() const
2672{
2673 return mDeleteStatus;
2674}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002675
2676void Program::validate()
2677{
2678 resetInfoLog();
2679
2680 if (!isLinked())
2681 {
2682 appendToInfoLog("Program has not been successfully linked.");
2683 mValidated = false;
2684 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002685 else
2686 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002687 applyUniforms();
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002688 if (!validateSamplers(true))
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002689 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002690 mValidated = false;
2691 }
2692 else
2693 {
2694 mValidated = true;
2695 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002696 }
2697}
2698
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002699bool Program::validateSamplers(bool logErrors)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002700{
2701 // if any two active samplers in a program are of different types, but refer to the same
2702 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2703 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002704
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002705 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002706 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2707
2708 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2709 {
2710 textureUnitType[i] = TEXTURE_UNKNOWN;
2711 }
2712
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00002713 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002714 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002715 if (mSamplersPS[i].active)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002716 {
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002717 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002718
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002719 if (unit >= maxCombinedTextureImageUnits)
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002720 {
2721 if (logErrors)
2722 {
2723 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
2724 }
2725
2726 return false;
2727 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002728
2729 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002730 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002731 if (mSamplersPS[i].textureType != textureUnitType[unit])
2732 {
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002733 if (logErrors)
2734 {
2735 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2736 }
2737
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002738 return false;
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002739 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002740 }
2741 else
2742 {
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002743 textureUnitType[unit] = mSamplersPS[i].textureType;
2744 }
2745 }
2746 }
2747
jbauman@chromium.orgb6e72222011-10-18 23:01:46 +00002748 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002749 {
2750 if (mSamplersVS[i].active)
2751 {
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002752 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002753
daniel@transgaming.comdfd57022011-05-11 15:37:25 +00002754 if (unit >= maxCombinedTextureImageUnits)
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002755 {
2756 if (logErrors)
2757 {
2758 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
2759 }
2760
2761 return false;
2762 }
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002763
2764 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2765 {
2766 if (mSamplersVS[i].textureType != textureUnitType[unit])
2767 {
daniel@transgaming.comf494c9c2011-05-11 15:37:05 +00002768 if (logErrors)
2769 {
2770 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2771 }
2772
daniel@transgaming.comd4a35172011-05-11 15:36:45 +00002773 return false;
2774 }
2775 }
2776 else
2777 {
2778 textureUnitType[unit] = mSamplersVS[i].textureType;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002779 }
2780 }
2781 }
2782
2783 return true;
2784}
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002785
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002786void Program::initializeConstantHandles(Uniform *targetUniform, Uniform::RegisterInfo *ri, ID3DXConstantTable *constantTable)
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002787{
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002788 D3DXHANDLE handle = constantTable->GetConstantByName(0, targetUniform->_name.c_str());
2789 if (handle)
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002790 {
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002791 UINT descriptionCount = 1;
2792 D3DXCONSTANT_DESC constantDescription;
2793 HRESULT result = constantTable->GetConstantDesc(handle, &constantDescription, &descriptionCount);
2794 ASSERT(SUCCEEDED(result));
2795 ri->registerIndex = constantDescription.RegisterIndex;
2796 ri->registerCount = constantDescription.RegisterCount;
2797 ri->registerSet = constantDescription.RegisterSet;
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002798 }
jbauman@chromium.org72e8f442011-10-20 00:22:01 +00002799 else
2800 {
2801 ri->registerCount = 0;
2802 }
daniel@transgaming.com2d84df02010-05-14 17:31:13 +00002803}
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002804
daniel@transgaming.com31754962010-11-28 02:02:52 +00002805GLint Program::getDxDepthRangeLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002806{
daniel@transgaming.com31754962010-11-28 02:02:52 +00002807 return mDxDepthRangeLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002808}
2809
2810GLint Program::getDxDepthLocation() const
2811{
2812 return mDxDepthLocation;
2813}
2814
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00002815GLint Program::getDxCoordLocation() const
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002816{
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +00002817 return mDxCoordLocation;
daniel@transgaming.com91fd1de2010-05-18 18:51:40 +00002818}
2819
2820GLint Program::getDxHalfPixelSizeLocation() const
2821{
2822 return mDxHalfPixelSizeLocation;
2823}
2824
2825GLint Program::getDxFrontCCWLocation() const
2826{
2827 return mDxFrontCCWLocation;
2828}
2829
2830GLint Program::getDxPointsOrLinesLocation() const
2831{
2832 return mDxPointsOrLinesLocation;
2833}
2834
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002835}