blob: e9717ccd5e6cdc6d91510f7d09eb769736f47ce2 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// 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.com4f39fd92010-03-08 20:26:45 +000018namespace gl
19{
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000020Uniform::Uniform(GLenum type, const std::string &name, unsigned int arraySize) : type(type), name(name), arraySize(arraySize)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021{
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000022 int bytes = UniformTypeSize(type) * arraySize;
23
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000024 this->data = new unsigned char[bytes];
25 memset(this->data, 0, bytes);
26}
27
28Uniform::~Uniform()
29{
30 delete[] data;
31}
32
33Program::Program()
34{
35 mFragmentShader = NULL;
36 mVertexShader = NULL;
37
38 mPixelExecutable = NULL;
39 mVertexExecutable = NULL;
40 mConstantTablePS = NULL;
41 mConstantTableVS = NULL;
42
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +000043 mPixelHLSL = NULL;
44 mVertexHLSL = NULL;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000045 mInfoLog = NULL;
46
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000047 unlink();
48
49 mDeleteStatus = false;
50}
51
52Program::~Program()
53{
54 unlink(true);
55}
56
57bool Program::attachShader(Shader *shader)
58{
59 if (shader->getType() == GL_VERTEX_SHADER)
60 {
61 if (mVertexShader)
62 {
63 return false;
64 }
65
66 mVertexShader = (VertexShader*)shader;
67 mVertexShader->attach();
68 }
69 else if (shader->getType() == GL_FRAGMENT_SHADER)
70 {
71 if (mFragmentShader)
72 {
73 return false;
74 }
75
76 mFragmentShader = (FragmentShader*)shader;
77 mFragmentShader->attach();
78 }
79 else UNREACHABLE();
80
81 return true;
82}
83
84bool Program::detachShader(Shader *shader)
85{
86 if (shader->getType() == GL_VERTEX_SHADER)
87 {
88 if (mVertexShader != shader)
89 {
90 return false;
91 }
92
93 mVertexShader->detach();
94 mVertexShader = NULL;
95 }
96 else if (shader->getType() == GL_FRAGMENT_SHADER)
97 {
98 if (mFragmentShader != shader)
99 {
100 return false;
101 }
102
103 mFragmentShader->detach();
104 mFragmentShader = NULL;
105 }
106 else UNREACHABLE();
107
108 unlink();
109
110 return true;
111}
112
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000113int Program::getAttachedShadersCount() const
114{
115 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
116}
117
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000118IDirect3DPixelShader9 *Program::getPixelShader()
119{
120 return mPixelExecutable;
121}
122
123IDirect3DVertexShader9 *Program::getVertexShader()
124{
125 return mVertexExecutable;
126}
127
128void Program::bindAttributeLocation(GLuint index, const char *name)
129{
130 if (index < MAX_VERTEX_ATTRIBS)
131 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000132 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
133 {
134 mAttributeBinding[i].erase(name);
135 }
136
137 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138 }
139}
140
141GLuint Program::getAttributeLocation(const char *name)
142{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000143 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000145 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000146 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000147 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000148 {
149 return index;
150 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151 }
152 }
153
154 return -1;
155}
156
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000157int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000158{
159 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
160 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000161 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000162 }
163
164 return -1;
165}
166
167// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
168// index referenced in the compiled HLSL shader
169GLint Program::getSamplerMapping(unsigned int samplerIndex)
170{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000171 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
172
173 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000175 return mSamplers[samplerIndex].logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000176 }
177
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000178 return -1;
179}
180
181SamplerType Program::getSamplerType(unsigned int samplerIndex)
182{
183 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
184 assert(mSamplers[samplerIndex].active);
185
186 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000187}
188
189GLint Program::getUniformLocation(const char *name)
190{
191 for (unsigned int location = 0; location < mUniforms.size(); location++)
192 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000193 if (mUniforms[location]->name == decorate(name))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000194 {
195 return location;
196 }
197 }
198
199 return -1;
200}
201
202bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
203{
204 if (location < 0 || location >= (int)mUniforms.size())
205 {
206 return false;
207 }
208
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000209 if (mUniforms[location]->type == GL_FLOAT)
210 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000211 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000212
213 if (arraySize == 1 && count > 1)
214 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
215
216 count = std::min(arraySize, count);
217
218 memcpy(mUniforms[location]->data, v, sizeof(GLfloat) * count);
219 }
220 else if (mUniforms[location]->type == GL_BOOL)
221 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000222 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000223
224 if (arraySize == 1 && count > 1)
225 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
226
227 count = std::min(arraySize, count);
228 GLboolean *boolParams = new GLboolean[count];
229
230 for (int i = 0; i < count; ++i)
231 {
232 if (v[i] == 0.0f)
233 {
234 boolParams[i] = GL_FALSE;
235 }
236 else
237 {
238 boolParams[i] = GL_TRUE;
239 }
240 }
241
242 memcpy(mUniforms[location]->data, boolParams, sizeof(GLboolean) * count);
243
244 delete [] boolParams;
245 }
246 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000247 {
248 return false;
249 }
250
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000251 return true;
252}
253
254bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
255{
256 if (location < 0 || location >= (int)mUniforms.size())
257 {
258 return false;
259 }
260
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000261 if (mUniforms[location]->type == GL_FLOAT_VEC2)
262 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000263 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000264
265 if (arraySize == 1 && count > 1)
266 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
267
268 count = std::min(arraySize, count);
269
270 memcpy(mUniforms[location]->data, v, 2 * sizeof(GLfloat) * count);
271 }
272 else if (mUniforms[location]->type == GL_BOOL_VEC2)
273 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000274 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000275
276 if (arraySize == 1 && count > 1)
277 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
278
279 count = std::min(arraySize, count);
280 GLboolean *boolParams = new GLboolean[count * 2];
281
282 for (int i = 0; i < count * 2; ++i)
283 {
284 if (v[i] == 0.0f)
285 {
286 boolParams[i] = GL_FALSE;
287 }
288 else
289 {
290 boolParams[i] = GL_TRUE;
291 }
292 }
293
294 memcpy(mUniforms[location]->data, boolParams, 2 * sizeof(GLboolean) * count);
295
296 delete [] boolParams;
297 }
298 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000299 {
300 return false;
301 }
302
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000303 return true;
304}
305
306bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
307{
308 if (location < 0 || location >= (int)mUniforms.size())
309 {
310 return false;
311 }
312
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000313 if (mUniforms[location]->type == GL_FLOAT_VEC3)
314 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000315 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000316
317 if (arraySize == 1 && count > 1)
318 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
319
320 count = std::min(arraySize, count);
321
322 memcpy(mUniforms[location]->data, v, 3 * sizeof(GLfloat) * count);
323 }
324 else if (mUniforms[location]->type == GL_BOOL_VEC3)
325 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000326 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000327
328 if (arraySize == 1 && count > 1)
329 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
330
331 count = std::min(arraySize, count);
332 GLboolean *boolParams = new GLboolean[count * 3];
333
334 for (int i = 0; i < count * 3; ++i)
335 {
336 if (v[i] == 0.0f)
337 {
338 boolParams[i] = GL_FALSE;
339 }
340 else
341 {
342 boolParams[i] = GL_TRUE;
343 }
344 }
345
346 memcpy(mUniforms[location]->data, boolParams, 3 * sizeof(GLboolean) * count);
347
348 delete [] boolParams;
349 }
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::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
359{
360 if (location < 0 || location >= (int)mUniforms.size())
361 {
362 return false;
363 }
364
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000365 if (mUniforms[location]->type == GL_FLOAT_VEC4)
366 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000367 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000368
369 if (arraySize == 1 && count > 1)
370 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
371
372 count = std::min(arraySize, count);
373
374 memcpy(mUniforms[location]->data, v, 4 * sizeof(GLfloat) * count);
375 }
376 else if (mUniforms[location]->type == GL_BOOL_VEC4)
377 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000378 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000379
380 if (arraySize == 1 && count > 1)
381 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
382
383 count = std::min(arraySize, count);
384 GLboolean *boolParams = new GLboolean[count * 4];
385
386 for (int i = 0; i < count * 4; ++i)
387 {
388 if (v[i] == 0.0f)
389 {
390 boolParams[i] = GL_FALSE;
391 }
392 else
393 {
394 boolParams[i] = GL_TRUE;
395 }
396 }
397
398 memcpy(mUniforms[location]->data, boolParams, 4 * sizeof(GLboolean) * count);
399
400 delete [] boolParams;
401 }
402 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000403 {
404 return false;
405 }
406
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000407 return true;
408}
409
410bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
411{
412 if (location < 0 || location >= (int)mUniforms.size())
413 {
414 return false;
415 }
416
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000417 if (mUniforms[location]->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000418 {
419 return false;
420 }
421
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000422 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000423
424 if (arraySize == 1 && count > 1)
425 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
426
427 count = std::min(arraySize, count);
428
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000429 memcpy(mUniforms[location]->data, value, 4 * sizeof(GLfloat) * count);
430
431 return true;
432}
433
434bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
435{
436 if (location < 0 || location >= (int)mUniforms.size())
437 {
438 return false;
439 }
440
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000441 if (mUniforms[location]->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442 {
443 return false;
444 }
445
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000446 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000447
448 if (arraySize == 1 && count > 1)
449 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
450
451 count = std::min(arraySize, count);
452
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000453 memcpy(mUniforms[location]->data, value, 9 * sizeof(GLfloat) * count);
454
455 return true;
456}
457
458bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
459{
460 if (location < 0 || location >= (int)mUniforms.size())
461 {
462 return false;
463 }
464
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000465 if (mUniforms[location]->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000466 {
467 return false;
468 }
469
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000470 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000471
472 if (arraySize == 1 && count > 1)
473 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
474
475 count = std::min(arraySize, count);
476
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000477 memcpy(mUniforms[location]->data, value, 16 * sizeof(GLfloat) * count);
478
479 return true;
480}
481
482bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
483{
484 if (location < 0 || location >= (int)mUniforms.size())
485 {
486 return false;
487 }
488
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000489 if (mUniforms[location]->type == GL_INT)
490 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000491 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000492
493 if (arraySize == 1 && count > 1)
494 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
495
496 count = std::min(arraySize, count);
497
498 memcpy(mUniforms[location]->data, v, sizeof(GLint) * count);
499 }
500 else if (mUniforms[location]->type == GL_BOOL)
501 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000502 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000503
504 if (arraySize == 1 && count > 1)
505 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
506
507 count = std::min(arraySize, count);
508 GLboolean *boolParams = new GLboolean[count];
509
510 for (int i = 0; i < count; ++i)
511 {
512 if (v[i] == 0)
513 {
514 boolParams[i] = GL_FALSE;
515 }
516 else
517 {
518 boolParams[i] = GL_TRUE;
519 }
520 }
521
522 memcpy(mUniforms[location]->data, boolParams, sizeof(GLboolean) * count);
523
524 delete [] boolParams;
525 }
526 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000527 {
528 return false;
529 }
530
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000531 return true;
532}
533
534bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
535{
536 if (location < 0 || location >= (int)mUniforms.size())
537 {
538 return false;
539 }
540
541 if (mUniforms[location]->type == GL_INT_VEC2)
542 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000543 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000544
545 if (arraySize == 1 && count > 1)
546 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
547
548 count = std::min(arraySize, count);
549
550 memcpy(mUniforms[location]->data, v, 2 * sizeof(GLint) * count);
551 }
552 else if (mUniforms[location]->type == GL_BOOL_VEC2)
553 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000554 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000555
556 if (arraySize == 1 && count > 1)
557 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
558
559 count = std::min(arraySize, count);
560 GLboolean *boolParams = new GLboolean[count * 2];
561
562 for (int i = 0; i < count * 2; ++i)
563 {
564 if (v[i] == 0)
565 {
566 boolParams[i] = GL_FALSE;
567 }
568 else
569 {
570 boolParams[i] = GL_TRUE;
571 }
572 }
573
574 memcpy(mUniforms[location]->data, boolParams, 2 * sizeof(GLboolean) * count);
575
576 delete [] boolParams;
577 }
578 else
579 {
580 return false;
581 }
582
583 return true;
584}
585
586bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
587{
588 if (location < 0 || location >= (int)mUniforms.size())
589 {
590 return false;
591 }
592
593 if (mUniforms[location]->type == GL_INT_VEC3)
594 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000595 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000596
597 if (arraySize == 1 && count > 1)
598 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
599
600 count = std::min(arraySize, count);
601
602 memcpy(mUniforms[location]->data, v, 3 * sizeof(GLint) * count);
603 }
604 else if (mUniforms[location]->type == GL_BOOL_VEC3)
605 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000606 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000607
608 if (arraySize == 1 && count > 1)
609 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
610
611 count = std::min(arraySize, count);
612 GLboolean *boolParams = new GLboolean[count * 3];
613
614 for (int i = 0; i < count * 3; ++i)
615 {
616 if (v[i] == 0)
617 {
618 boolParams[i] = GL_FALSE;
619 }
620 else
621 {
622 boolParams[i] = GL_TRUE;
623 }
624 }
625
626 memcpy(mUniforms[location]->data, boolParams, 3 * sizeof(GLboolean) * count);
627
628 delete [] boolParams;
629 }
630 else
631 {
632 return false;
633 }
634
635 return true;
636}
637
638bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
639{
640 if (location < 0 || location >= (int)mUniforms.size())
641 {
642 return false;
643 }
644
645 if (mUniforms[location]->type == GL_INT_VEC4)
646 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000647 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000648
649 if (arraySize == 1 && count > 1)
650 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
651
652 count = std::min(arraySize, count);
653
654 memcpy(mUniforms[location]->data, v, 4 * sizeof(GLint) * count);
655 }
656 else if (mUniforms[location]->type == GL_BOOL_VEC4)
657 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000658 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000659
660 if (arraySize == 1 && count > 1)
661 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
662
663 count = std::min(arraySize, count);
664 GLboolean *boolParams = new GLboolean[count * 4];
665
666 for (int i = 0; i < count * 4; ++i)
667 {
668 if (v[i] == 0)
669 {
670 boolParams[i] = GL_FALSE;
671 }
672 else
673 {
674 boolParams[i] = GL_TRUE;
675 }
676 }
677
678 memcpy(mUniforms[location]->data, boolParams, 4 * sizeof(GLboolean) * count);
679
680 delete [] boolParams;
681 }
682 else
683 {
684 return false;
685 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000686
687 return true;
688}
689
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000690bool Program::getUniformfv(GLint location, GLfloat *params)
691{
692 if (location < 0 || location >= (int)mUniforms.size())
693 {
694 return false;
695 }
696
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000697 unsigned int count = UniformComponentCount(mUniforms[location]->type);
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000698
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000699 switch (UniformComponentType(mUniforms[location]->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000700 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000701 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000702 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000703 GLboolean *boolParams = (GLboolean*)mUniforms[location]->data;
704
705 for (unsigned int i = 0; i < count; ++i)
706 {
707 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
708 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000709 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000710 break;
711 case GL_FLOAT:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000712 memcpy(params, mUniforms[location]->data, count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000713 break;
714 case GL_INT:
715 {
716 GLint *intParams = (GLint*)mUniforms[location]->data;
717
718 for (unsigned int i = 0; i < count; ++i)
719 {
720 params[i] = (float)intParams[i];
721 }
722 }
723 break;
724 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000725 }
726
727 return true;
728}
729
730bool Program::getUniformiv(GLint location, GLint *params)
731{
732 if (location < 0 || location >= (int)mUniforms.size())
733 {
734 return false;
735 }
736
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000737 unsigned int count = UniformComponentCount(mUniforms[location]->type);
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000738
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000739 switch (UniformComponentType(mUniforms[location]->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000740 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000741 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000742 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000743 GLboolean *boolParams = (GLboolean*)mUniforms[location]->data;
744
745 for (unsigned int i = 0; i < count; ++i)
746 {
747 params[i] = (GLint)boolParams[i];
748 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000749 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000750 break;
751 case GL_FLOAT:
752 {
753 GLfloat *floatParams = (GLfloat*)mUniforms[location]->data;
754
755 for (unsigned int i = 0; i < count; ++i)
756 {
757 params[i] = (GLint)floatParams[i];
758 }
759 }
760 break;
761 case GL_INT:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000762 memcpy(params, mUniforms[location]->data, count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000763 break;
764 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000765 }
766
767 return true;
768}
769
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000770// Applies all the uniforms set for this program object to the Direct3D 9 device
771void Program::applyUniforms()
772{
773 for (unsigned int location = 0; location < mUniforms.size(); location++)
774 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000775 int arraySize = mUniforms[location]->arraySize;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000776 GLfloat *f = (GLfloat*)mUniforms[location]->data;
777 GLint *i = (GLint*)mUniforms[location]->data;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000778 GLboolean *b = (GLboolean*)mUniforms[location]->data;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000779
780 switch (mUniforms[location]->type)
781 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000782 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
783 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
784 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
785 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
786 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
787 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
788 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
789 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
790 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
791 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
792 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
793 case GL_INT: applyUniform1iv(location, arraySize, i); break;
794 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
795 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
796 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000797 default:
798 UNIMPLEMENTED(); // FIXME
799 UNREACHABLE();
800 }
801 }
802}
803
804// Compiles the HLSL code of the attached shaders into executable binaries
805ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
806{
807 if (!hlsl)
808 {
809 return NULL;
810 }
811
812 ID3DXBuffer *binary = NULL;
813 ID3DXBuffer *errorMessage = NULL;
814
daniel@transgaming.comcbbca002010-04-01 13:39:32 +0000815 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000816
817 if (SUCCEEDED(result))
818 {
819 return binary;
820 }
821
822 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
823 {
824 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
825 }
826
827 if (errorMessage)
828 {
829 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000830
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000831 TRACE("\n%s", hlsl);
832 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000833 }
834
835 return NULL;
836}
837
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000838void Program::parseVaryings(const char *structure, char *hlsl, VaryingArray &varyings)
839{
840 char *input = strstr(hlsl, structure);
841 input += strlen(structure);
842
843 while (input && *input != '}')
844 {
845 char varyingType[256];
846 char varyingName[256];
847 unsigned int semanticIndex;
848 int matches = sscanf(input, " %s %s : TEXCOORD%d;", varyingType, varyingName, &semanticIndex);
849
850 if (matches == 3)
851 {
852 ASSERT(semanticIndex <= 9); // Single character
853
854 varyings.push_back(Varying(varyingName, input));
855 }
856
857 input = strstr(input, ";");
858 input += 2;
859 }
860}
861
862bool Program::linkVaryings()
863{
864 if (!mPixelHLSL || !mVertexHLSL)
865 {
866 return false;
867 }
868
869 VaryingArray vertexVaryings;
870 VaryingArray pixelVaryings;
871
872 parseVaryings("struct VS_OUTPUT\n{\n", mVertexHLSL, vertexVaryings);
873 parseVaryings("struct PS_INPUT\n{\n", mPixelHLSL, pixelVaryings);
874
875 for (unsigned int out = 0; out < vertexVaryings.size(); out++)
876 {
877 unsigned int in;
878 for (in = 0; in < pixelVaryings.size(); in++)
879 {
880 if (vertexVaryings[out].name == pixelVaryings[in].name)
881 {
882 pixelVaryings[in].link = out;
883 vertexVaryings[out].link = in;
884
885 break;
886 }
887 }
888
889 if (in != pixelVaryings.size())
890 {
891 // FIXME: Verify matching type and qualifiers
892
893 char *outputSemantic = strstr(vertexVaryings[out].declaration, " : TEXCOORD");
894 char *inputSemantic = strstr(pixelVaryings[in].declaration, " : TEXCOORD");
895 outputSemantic[11] = inputSemantic[11];
896 }
897 else
898 {
899 // Comment out the declaration and output assignment
900 vertexVaryings[out].declaration[0] = '/';
901 vertexVaryings[out].declaration[1] = '/';
902
903 char outputString[256];
904 sprintf(outputString, " output.%s = ", vertexVaryings[out].name.c_str());
905 char *varyingOutput = strstr(mVertexHLSL, outputString);
906
907 varyingOutput[0] = '/';
908 varyingOutput[1] = '/';
909 }
910 }
911
912 // Verify that each pixel varying has been linked to a vertex varying
913 for (unsigned int in = 0; in < pixelVaryings.size(); in++)
914 {
915 if (pixelVaryings[in].link < 0)
916 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000917 appendToInfoLog("Pixel varying (%s) does not match any vertex varying", pixelVaryings[in].name);
918
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000919 return false;
920 }
921 }
922
923 return true;
924}
925
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000926// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
927// compiling them into binaries, determining the attribute mappings, and collecting
928// a list of uniforms
929void Program::link()
930{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000931 unlink();
932
933 if (!mFragmentShader || !mFragmentShader->isCompiled())
934 {
935 return;
936 }
937
938 if (!mVertexShader || !mVertexShader->isCompiled())
939 {
940 return;
941 }
942
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +0000943 Context *context = getContext();
944 const char *vertexProfile = context->getVertexShaderProfile();
945 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +0000946
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000947 const char *ps = mFragmentShader->getHLSL();
948 const char *vs = mVertexShader->getHLSL();
949
950 mPixelHLSL = new char[strlen(ps) + 1];
951 strcpy(mPixelHLSL, ps);
952 mVertexHLSL = new char[strlen(vs) + 1];
953 strcpy(mVertexHLSL, vs);
954
955 if (!linkVaryings())
956 {
957 return;
958 }
959
960 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL, vertexProfile, &mConstantTableVS);
961 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000962
963 if (vertexBinary && pixelBinary)
964 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +0000965 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000966 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
967 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
968
969 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
970 {
971 return error(GL_OUT_OF_MEMORY);
972 }
973
974 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000975
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000976 vertexBinary->Release();
977 pixelBinary->Release();
978 vertexBinary = NULL;
979 pixelBinary = NULL;
980
981 if (mVertexExecutable && mPixelExecutable)
982 {
983 if (!linkAttributes())
984 {
985 return;
986 }
987
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000988 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000989 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000990 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000991 }
992
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000993 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000994 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000995 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000996 }
997
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000998 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000999 }
1000 }
1001}
1002
1003// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1004bool Program::linkAttributes()
1005{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001006 // Link attributes that have a binding location
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001007 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1008 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001009 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1010 int location = getAttributeBinding(attribute.name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001011
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001012 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001013 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001014 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001015 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001016 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001017 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001018
daniel@transgaming.com85423182010-04-22 13:35:27 +00001019 mLinkedAttribute[location] = attribute;
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001020 }
1021 }
1022
1023 // Link attributes that don't have a binding location
1024 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS + 1; attributeIndex++)
1025 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001026 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1027 int location = getAttributeBinding(attribute.name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001028
1029 if (location == -1) // Not set by glBindAttribLocation
1030 {
1031 int availableIndex = 0;
1032
daniel@transgaming.com85423182010-04-22 13:35:27 +00001033 while (availableIndex < MAX_VERTEX_ATTRIBS && !mLinkedAttribute[availableIndex].name.empty())
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001034 {
1035 availableIndex++;
1036 }
1037
1038 if (availableIndex == MAX_VERTEX_ATTRIBS)
1039 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001040 appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001041
1042 return false; // Fail to link
1043 }
1044
daniel@transgaming.com85423182010-04-22 13:35:27 +00001045 mLinkedAttribute[availableIndex] = attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001046 }
1047 }
1048
1049 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1050 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001051 mSemanticIndex[attributeIndex] = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001052 }
1053
1054 return true;
1055}
1056
daniel@transgaming.com85423182010-04-22 13:35:27 +00001057int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001058{
1059 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1060 {
1061 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1062 {
1063 return location;
1064 }
1065 }
1066
1067 return -1;
1068}
1069
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001070bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1071{
1072 D3DXCONSTANTTABLE_DESC constantTableDescription;
1073 D3DXCONSTANT_DESC constantDescription;
1074 UINT descriptionCount = 1;
1075
1076 constantTable->GetDesc(&constantTableDescription);
1077
1078 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1079 {
1080 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1081 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1082
1083 if (!defineUniform(constantHandle, constantDescription))
1084 {
1085 return false;
1086 }
1087 }
1088
1089 return true;
1090}
1091
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001092// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001093// Returns true if succesful (uniform not already defined)
1094bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1095{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001096 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1097 {
1098 unsigned int samplerIndex = constantDescription.RegisterIndex;
1099
1100 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1101
1102 mSamplers[samplerIndex].active = true;
1103 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1104 mSamplers[samplerIndex].logicalTextureUnit = 0;
1105 }
1106
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001107 switch(constantDescription.Class)
1108 {
1109 case D3DXPC_STRUCT:
1110 {
1111 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1112 {
1113 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1114
1115 D3DXCONSTANT_DESC fieldDescription;
1116 UINT descriptionCount = 1;
1117
1118 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1119
1120 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1121 {
1122 return false;
1123 }
1124 }
1125
1126 return true;
1127 }
1128 case D3DXPC_SCALAR:
1129 case D3DXPC_VECTOR:
1130 case D3DXPC_MATRIX_COLUMNS:
1131 case D3DXPC_OBJECT:
1132 return defineUniform(constantDescription, name + constantDescription.Name);
1133 default:
1134 UNREACHABLE();
1135 return false;
1136 }
1137}
1138
1139bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1140{
1141 Uniform *uniform = createUniform(constantDescription, name);
1142
1143 if(!uniform)
1144 {
1145 return false;
1146 }
1147
1148 // Check if already defined
1149 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001150 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001151
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001152 if (location >= 0)
1153 {
1154 delete uniform;
1155
1156 if (mUniforms[location]->type != type)
1157 {
1158 return false;
1159 }
1160 else
1161 {
1162 return true;
1163 }
1164 }
1165
1166 mUniforms.push_back(uniform);
1167
1168 return true;
1169}
1170
1171Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001172{
1173 if (constantDescription.Rows == 1) // Vectors and scalars
1174 {
1175 switch (constantDescription.Type)
1176 {
1177 case D3DXPT_SAMPLER2D:
1178 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001179 switch (constantDescription.Columns)
1180 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001181 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001182 default: UNREACHABLE();
1183 }
1184 break;
1185 case D3DXPT_BOOL:
1186 switch (constantDescription.Columns)
1187 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001188 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1189 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1190 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1191 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001192 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001193 }
1194 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001195 case D3DXPT_INT:
1196 switch (constantDescription.Columns)
1197 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001198 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1199 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1200 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1201 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001202 default: UNREACHABLE();
1203 }
1204 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001205 case D3DXPT_FLOAT:
1206 switch (constantDescription.Columns)
1207 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001208 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1209 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1210 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1211 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001212 default: UNREACHABLE();
1213 }
1214 break;
1215 default:
1216 UNIMPLEMENTED(); // FIXME
1217 UNREACHABLE();
1218 }
1219 }
1220 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1221 {
1222 switch (constantDescription.Type)
1223 {
1224 case D3DXPT_FLOAT:
1225 switch (constantDescription.Rows)
1226 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001227 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1228 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1229 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001230 default: UNREACHABLE();
1231 }
1232 break;
1233 default: UNREACHABLE();
1234 }
1235 }
1236 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001237
1238 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001239}
1240
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001241// This methods needs to match OutputHLSL::decorate
1242std::string Program::decorate(const std::string &string)
1243{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001244 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001245 {
1246 return "_" + string;
1247 }
1248 else
1249 {
1250 return string;
1251 }
1252}
1253
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001254bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1255{
1256 BOOL *vector = new BOOL[count];
1257 for (int i = 0; i < count; i++)
1258 {
1259 if (v[i] == GL_FALSE)
1260 vector[i] = 0;
1261 else
1262 vector[i] = 1;
1263 }
1264
1265 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1266 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1267 IDirect3DDevice9 *device = getDevice();
1268
1269 if (constantPS)
1270 {
1271 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1272 }
1273
1274 if (constantVS)
1275 {
1276 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1277 }
1278
1279 delete [] vector;
1280
1281 return true;
1282}
1283
1284bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1285{
1286 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1287
1288 for (int i = 0; i < count; i++)
1289 {
1290 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1291 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1292
1293 v += 2;
1294 }
1295
1296 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1297 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1298 IDirect3DDevice9 *device = getDevice();
1299
1300 if (constantPS)
1301 {
1302 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1303 }
1304
1305 if (constantVS)
1306 {
1307 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1308 }
1309
1310 delete[] vector;
1311
1312 return true;
1313}
1314
1315bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1316{
1317 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1318
1319 for (int i = 0; i < count; i++)
1320 {
1321 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1322 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1323 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1324
1325 v += 3;
1326 }
1327
1328 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1329 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1330 IDirect3DDevice9 *device = getDevice();
1331
1332 if (constantPS)
1333 {
1334 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1335 }
1336
1337 if (constantVS)
1338 {
1339 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1340 }
1341
1342 delete[] vector;
1343
1344 return true;
1345}
1346
1347bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1348{
1349 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1350
1351 for (int i = 0; i < count; i++)
1352 {
1353 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1354 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1355 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1356 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1357
1358 v += 3;
1359 }
1360
1361 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1362 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1363 IDirect3DDevice9 *device = getDevice();
1364
1365 if (constantPS)
1366 {
1367 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1368 }
1369
1370 if (constantVS)
1371 {
1372 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1373 }
1374
1375 delete [] vector;
1376
1377 return true;
1378}
1379
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001380bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1381{
1382 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1383 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1384 IDirect3DDevice9 *device = getDevice();
1385
1386 if (constantPS)
1387 {
1388 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1389 }
1390
1391 if (constantVS)
1392 {
1393 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1394 }
1395
1396 return true;
1397}
1398
1399bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1400{
1401 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1402
1403 for (int i = 0; i < count; i++)
1404 {
1405 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1406
1407 v += 2;
1408 }
1409
1410 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1411 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1412 IDirect3DDevice9 *device = getDevice();
1413
1414 if (constantPS)
1415 {
1416 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1417 }
1418
1419 if (constantVS)
1420 {
1421 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1422 }
1423
1424 delete[] vector;
1425
1426 return true;
1427}
1428
1429bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1430{
1431 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1432
1433 for (int i = 0; i < count; i++)
1434 {
1435 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1436
1437 v += 3;
1438 }
1439
1440 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1441 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1442 IDirect3DDevice9 *device = getDevice();
1443
1444 if (constantPS)
1445 {
1446 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1447 }
1448
1449 if (constantVS)
1450 {
1451 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1452 }
1453
1454 delete[] vector;
1455
1456 return true;
1457}
1458
1459bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1460{
1461 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1462 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1463 IDirect3DDevice9 *device = getDevice();
1464
1465 if (constantPS)
1466 {
1467 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
1468 }
1469
1470 if (constantVS)
1471 {
1472 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
1473 }
1474
1475 return true;
1476}
1477
1478bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
1479{
1480 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1481
1482 for (int i = 0; i < count; i++)
1483 {
1484 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
1485 value[1], value[3], 0, 0,
1486 0, 0, 1, 0,
1487 0, 0, 0, 1);
1488
1489 value += 4;
1490 }
1491
1492 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1493 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1494 IDirect3DDevice9 *device = getDevice();
1495
1496 if (constantPS)
1497 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001498 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001499 }
1500
1501 if (constantVS)
1502 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001503 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001504 }
1505
1506 delete[] matrix;
1507
1508 return true;
1509}
1510
1511bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
1512{
1513 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1514
1515 for (int i = 0; i < count; i++)
1516 {
1517 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
1518 value[1], value[4], value[7], 0,
1519 value[2], value[5], value[8], 0,
1520 0, 0, 0, 1);
1521
1522 value += 9;
1523 }
1524
1525 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1526 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1527 IDirect3DDevice9 *device = getDevice();
1528
1529 if (constantPS)
1530 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001531 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001532 }
1533
1534 if (constantVS)
1535 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001536 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001537 }
1538
1539 delete[] matrix;
1540
1541 return true;
1542}
1543
1544bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
1545{
1546 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1547
1548 for (int i = 0; i < count; i++)
1549 {
1550 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
1551 value[1], value[5], value[9], value[13],
1552 value[2], value[6], value[10], value[14],
1553 value[3], value[7], value[11], value[15]);
1554
1555 value += 16;
1556 }
1557
1558 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1559 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1560 IDirect3DDevice9 *device = getDevice();
1561
1562 if (constantPS)
1563 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001564 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001565 }
1566
1567 if (constantVS)
1568 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001569 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001570 }
1571
1572 delete[] matrix;
1573
1574 return true;
1575}
1576
1577bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
1578{
1579 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1580 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1581 IDirect3DDevice9 *device = getDevice();
1582
1583 if (constantPS)
1584 {
1585 D3DXCONSTANT_DESC constantDescription;
1586 UINT descriptionCount = 1;
1587 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
1588
daniel@transgaming.com2884b782010-03-08 21:30:48 +00001589 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001590 {
1591 return false;
1592 }
1593
1594 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1595 {
1596 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
1597
1598 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
1599 {
1600 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001601
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001602 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
1603 {
1604 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1605 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001606 ASSERT(mSamplers[samplerIndex].active);
1607 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001608 }
1609 }
1610 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001611
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001612 return true;
1613 }
1614 }
1615
1616 if (constantPS)
1617 {
1618 mConstantTablePS->SetIntArray(device, constantPS, v, count);
1619 }
1620
1621 if (constantVS)
1622 {
1623 mConstantTableVS->SetIntArray(device, constantVS, v, count);
1624 }
1625
1626 return true;
1627}
1628
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001629bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
1630{
1631 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1632
1633 for (int i = 0; i < count; i++)
1634 {
1635 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
1636
1637 v += 2;
1638 }
1639
1640 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1641 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1642 IDirect3DDevice9 *device = getDevice();
1643
1644 if (constantPS)
1645 {
1646 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1647 }
1648
1649 if (constantVS)
1650 {
1651 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1652 }
1653
1654 delete[] vector;
1655
1656 return true;
1657}
1658
1659bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
1660{
1661 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1662
1663 for (int i = 0; i < count; i++)
1664 {
1665 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
1666
1667 v += 3;
1668 }
1669
1670 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1671 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1672 IDirect3DDevice9 *device = getDevice();
1673
1674 if (constantPS)
1675 {
1676 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1677 }
1678
1679 if (constantVS)
1680 {
1681 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1682 }
1683
1684 delete[] vector;
1685
1686 return true;
1687}
1688
1689bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
1690{
1691 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1692
1693 for (int i = 0; i < count; i++)
1694 {
1695 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
1696
1697 v += 4;
1698 }
1699
1700 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1701 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1702 IDirect3DDevice9 *device = getDevice();
1703
1704 if (constantPS)
1705 {
1706 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1707 }
1708
1709 if (constantVS)
1710 {
1711 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1712 }
1713
1714 delete [] vector;
1715
1716 return true;
1717}
1718
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001719void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001720{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001721 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001722 {
1723 return;
1724 }
1725
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001726 char info[1024];
1727
1728 va_list vararg;
1729 va_start(vararg, format);
1730 vsnprintf(info, sizeof(info), format, vararg);
1731 va_end(vararg);
1732
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001733 size_t infoLength = strlen(info);
1734
1735 if (!mInfoLog)
1736 {
1737 mInfoLog = new char[infoLength + 1];
1738 strcpy(mInfoLog, info);
1739 }
1740 else
1741 {
1742 size_t logLength = strlen(mInfoLog);
1743 char *newLog = new char[logLength + infoLength + 1];
1744 strcpy(newLog, mInfoLog);
1745 strcpy(newLog + logLength, info);
1746
1747 delete[] mInfoLog;
1748 mInfoLog = newLog;
1749 }
1750}
1751
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001752// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
1753void Program::unlink(bool destroy)
1754{
1755 if (destroy) // Object being destructed
1756 {
1757 if (mFragmentShader)
1758 {
1759 mFragmentShader->detach();
1760 mFragmentShader = NULL;
1761 }
1762
1763 if (mVertexShader)
1764 {
1765 mVertexShader->detach();
1766 mVertexShader = NULL;
1767 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001768 }
1769
1770 if (mPixelExecutable)
1771 {
1772 mPixelExecutable->Release();
1773 mPixelExecutable = NULL;
1774 }
1775
1776 if (mVertexExecutable)
1777 {
1778 mVertexExecutable->Release();
1779 mVertexExecutable = NULL;
1780 }
1781
1782 if (mConstantTablePS)
1783 {
1784 mConstantTablePS->Release();
1785 mConstantTablePS = NULL;
1786 }
1787
1788 if (mConstantTableVS)
1789 {
1790 mConstantTableVS->Release();
1791 mConstantTableVS = NULL;
1792 }
1793
1794 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1795 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001796 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001797 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001798 }
1799
1800 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
1801 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001802 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001803 }
1804
1805 while (!mUniforms.empty())
1806 {
1807 delete mUniforms.back();
1808 mUniforms.pop_back();
1809 }
1810
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001811 delete[] mPixelHLSL;
1812 mPixelHLSL = NULL;
1813
1814 delete[] mVertexHLSL;
1815 mVertexHLSL = NULL;
1816
1817 delete[] mInfoLog;
1818 mInfoLog = NULL;
1819
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001820 mLinked = false;
1821}
1822
1823bool Program::isLinked()
1824{
1825 return mLinked;
1826}
1827
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001828int Program::getInfoLogLength() const
1829{
1830 if (!mInfoLog)
1831 {
1832 return 0;
1833 }
1834 else
1835 {
1836 return strlen(mInfoLog) + 1;
1837 }
1838}
1839
1840void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
1841{
1842 int index = 0;
1843
1844 if (mInfoLog)
1845 {
1846 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
1847 {
1848 infoLog[index] = mInfoLog[index];
1849 index++;
1850 }
1851 }
1852
1853 if (bufSize)
1854 {
1855 infoLog[index] = '\0';
1856 }
1857
1858 if (length)
1859 {
1860 *length = index;
1861 }
1862}
1863
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001864void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
1865{
1866 int total = 0;
1867
1868 if (mVertexShader)
1869 {
1870 if (total < maxCount)
1871 {
1872 shaders[total] = mVertexShader->getHandle();
1873 }
1874
1875 total++;
1876 }
1877
1878 if (mFragmentShader)
1879 {
1880 if (total < maxCount)
1881 {
1882 shaders[total] = mFragmentShader->getHandle();
1883 }
1884
1885 total++;
1886 }
1887
1888 if (count)
1889 {
1890 *count = total;
1891 }
1892}
1893
daniel@transgaming.com85423182010-04-22 13:35:27 +00001894void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
1895{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001896 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00001897 for (unsigned int i = 0; i < index; i++)
1898 {
1899 do
1900 {
1901 attribute++;
1902
1903 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
1904 }
1905 while (mLinkedAttribute[attribute].name.empty());
1906 }
1907
1908 if (bufsize > 0)
1909 {
1910 const char *string = mLinkedAttribute[attribute].name.c_str();
1911
1912 strncpy(name, string, bufsize);
1913 name[bufsize - 1] = '\0';
1914
1915 if (length)
1916 {
1917 *length = strlen(name);
1918 }
1919 }
1920
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001921 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00001922
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001923 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00001924}
1925
1926GLint Program::getActiveAttributeCount()
1927{
1928 int count = 0;
1929
1930 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1931 {
1932 if (!mLinkedAttribute[attributeIndex].name.empty())
1933 {
1934 count++;
1935 }
1936 }
1937
1938 return count;
1939}
1940
1941GLint Program::getActiveAttributeMaxLength()
1942{
1943 int maxLength = 0;
1944
1945 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1946 {
1947 if (!mLinkedAttribute[attributeIndex].name.empty())
1948 {
1949 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
1950 }
1951 }
1952
1953 return maxLength;
1954}
1955
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001956void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
1957{
1958 unsigned int uniform = 0;
1959 for (unsigned int i = 0; i < index; i++)
1960 {
1961 do
1962 {
1963 uniform++;
1964
1965 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
1966 }
1967 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
1968 }
1969
1970 if (bufsize > 0)
1971 {
1972 const char *string = mUniforms[uniform]->name.c_str();
1973
1974 if(string[0] == '_') // Undecorate
1975 {
1976 string++;
1977 }
1978
1979 strncpy(name, string, bufsize);
1980 name[bufsize - 1] = '\0';
1981
1982 if (length)
1983 {
1984 *length = strlen(name);
1985 }
1986 }
1987
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001988 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001989
1990 *type = mUniforms[uniform]->type;
1991}
1992
1993GLint Program::getActiveUniformCount()
1994{
1995 int count = 0;
1996
1997 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
1998 {
1999 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2000 {
2001 count++;
2002 }
2003 }
2004
2005 return count;
2006}
2007
2008GLint Program::getActiveUniformMaxLength()
2009{
2010 int maxLength = 0;
2011
2012 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2013 {
2014 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2015 {
2016 maxLength = std::max((int)(mUniforms[uniformIndex]->name.length() + 1), maxLength);
2017 }
2018 }
2019
2020 return maxLength;
2021}
2022
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002023void Program::flagForDeletion()
2024{
2025 mDeleteStatus = true;
2026}
2027
2028bool Program::isFlaggedForDeletion() const
2029{
2030 return mDeleteStatus;
2031}
2032}