blob: 0e73852cab62a94ad8696df2ea81650307f0561e [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
10#include "Program.h"
11
12#include "main.h"
13#include "Shader.h"
14#include "debug.h"
15
16namespace gl
17{
18Uniform::Uniform(UniformType type, const std::string &name, unsigned int bytes) : type(type), name(name), bytes(bytes)
19{
20 this->data = new unsigned char[bytes];
21 memset(this->data, 0, bytes);
22}
23
24Uniform::~Uniform()
25{
26 delete[] data;
27}
28
29Program::Program()
30{
31 mFragmentShader = NULL;
32 mVertexShader = NULL;
33
34 mPixelExecutable = NULL;
35 mVertexExecutable = NULL;
36 mConstantTablePS = NULL;
37 mConstantTableVS = NULL;
38
39 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
40 {
41 mAttributeName[index] = NULL;
42 }
43
44 unlink();
45
46 mDeleteStatus = false;
47}
48
49Program::~Program()
50{
51 unlink(true);
52}
53
54bool Program::attachShader(Shader *shader)
55{
56 if (shader->getType() == GL_VERTEX_SHADER)
57 {
58 if (mVertexShader)
59 {
60 return false;
61 }
62
63 mVertexShader = (VertexShader*)shader;
64 mVertexShader->attach();
65 }
66 else if (shader->getType() == GL_FRAGMENT_SHADER)
67 {
68 if (mFragmentShader)
69 {
70 return false;
71 }
72
73 mFragmentShader = (FragmentShader*)shader;
74 mFragmentShader->attach();
75 }
76 else UNREACHABLE();
77
78 return true;
79}
80
81bool Program::detachShader(Shader *shader)
82{
83 if (shader->getType() == GL_VERTEX_SHADER)
84 {
85 if (mVertexShader != shader)
86 {
87 return false;
88 }
89
90 mVertexShader->detach();
91 mVertexShader = NULL;
92 }
93 else if (shader->getType() == GL_FRAGMENT_SHADER)
94 {
95 if (mFragmentShader != shader)
96 {
97 return false;
98 }
99
100 mFragmentShader->detach();
101 mFragmentShader = NULL;
102 }
103 else UNREACHABLE();
104
105 unlink();
106
107 return true;
108}
109
110IDirect3DPixelShader9 *Program::getPixelShader()
111{
112 return mPixelExecutable;
113}
114
115IDirect3DVertexShader9 *Program::getVertexShader()
116{
117 return mVertexExecutable;
118}
119
120void Program::bindAttributeLocation(GLuint index, const char *name)
121{
122 if (index < MAX_VERTEX_ATTRIBS)
123 {
124 delete[] mAttributeName[index];
125 mAttributeName[index] = new char[strlen(name) + 1];
126 strcpy(mAttributeName[index], name);
127 }
128}
129
130GLuint Program::getAttributeLocation(const char *name)
131{
132 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
133 {
134 if (mAttributeName[index] && strcmp(mAttributeName[index], name) == 0)
135 {
136 return index;
137 }
138 }
139
140 return -1;
141}
142
143bool Program::isActiveAttribute(int attributeIndex)
144{
145 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
146 {
147 return mInputMapping[attributeIndex] != -1;
148 }
149
150 return false;
151}
152
153int Program::getInputMapping(int attributeIndex)
154{
155 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
156 {
157 return mInputMapping[attributeIndex];
158 }
159
160 return -1;
161}
162
163// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
164// index referenced in the compiled HLSL shader
165GLint Program::getSamplerMapping(unsigned int samplerIndex)
166{
167 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
168 {
169 return mSamplerMapping[samplerIndex];
170 }
171
172 return 0;
173}
174
175GLint Program::getUniformLocation(const char *name)
176{
177 for (unsigned int location = 0; location < mUniforms.size(); location++)
178 {
179 if (mUniforms[location]->name == name)
180 {
181 return location;
182 }
183 }
184
185 return -1;
186}
187
188bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
189{
190 if (location < 0 || location >= (int)mUniforms.size())
191 {
192 return false;
193 }
194
195 if (mUniforms[location]->type != UNIFORM_1FV || mUniforms[location]->bytes < sizeof(GLfloat) * count)
196 {
197 return false;
198 }
199
200 memcpy(mUniforms[location]->data, v, sizeof(GLfloat) * count);
201
202 return true;
203}
204
205bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
206{
207 if (location < 0 || location >= (int)mUniforms.size())
208 {
209 return false;
210 }
211
212 if (mUniforms[location]->type != UNIFORM_2FV || mUniforms[location]->bytes < 2 * sizeof(GLfloat) * count)
213 {
214 return false;
215 }
216
217 memcpy(mUniforms[location]->data, v, 2 * sizeof(GLfloat) * count);
218
219 return true;
220}
221
222bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
223{
224 if (location < 0 || location >= (int)mUniforms.size())
225 {
226 return false;
227 }
228
229 if (mUniforms[location]->type != UNIFORM_3FV || mUniforms[location]->bytes < 3 * sizeof(GLfloat) * count)
230 {
231 return false;
232 }
233
234 memcpy(mUniforms[location]->data, v, 3 * sizeof(GLfloat) * count);
235
236 return true;
237}
238
239bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
240{
241 if (location < 0 || location >= (int)mUniforms.size())
242 {
243 return false;
244 }
245
246 if (mUniforms[location]->type != UNIFORM_4FV || mUniforms[location]->bytes < 4 * sizeof(GLfloat) * count)
247 {
248 return false;
249 }
250
251 memcpy(mUniforms[location]->data, v, 4 * sizeof(GLfloat) * count);
252
253 return true;
254}
255
256bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
257{
258 if (location < 0 || location >= (int)mUniforms.size())
259 {
260 return false;
261 }
262
263 if (mUniforms[location]->type != UNIFORM_MATRIX_2FV || mUniforms[location]->bytes < 4 * sizeof(GLfloat) * count)
264 {
265 return false;
266 }
267
268 memcpy(mUniforms[location]->data, value, 4 * sizeof(GLfloat) * count);
269
270 return true;
271}
272
273bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
274{
275 if (location < 0 || location >= (int)mUniforms.size())
276 {
277 return false;
278 }
279
280 if (mUniforms[location]->type != UNIFORM_MATRIX_3FV || mUniforms[location]->bytes < 9 * sizeof(GLfloat) * count)
281 {
282 return false;
283 }
284
285 memcpy(mUniforms[location]->data, value, 9 * sizeof(GLfloat) * count);
286
287 return true;
288}
289
290bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
291{
292 if (location < 0 || location >= (int)mUniforms.size())
293 {
294 return false;
295 }
296
297 if (mUniforms[location]->type != UNIFORM_MATRIX_4FV || mUniforms[location]->bytes < 16 * sizeof(GLfloat) * count)
298 {
299 return false;
300 }
301
302 memcpy(mUniforms[location]->data, value, 16 * sizeof(GLfloat) * count);
303
304 return true;
305}
306
307bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
308{
309 if (location < 0 || location >= (int)mUniforms.size())
310 {
311 return false;
312 }
313
314 if (mUniforms[location]->type != UNIFORM_1IV || mUniforms[location]->bytes < sizeof(GLint) * count)
315 {
316 return false;
317 }
318
319 memcpy(mUniforms[location]->data, v, sizeof(GLint) * count);
320
321 return true;
322}
323
324// Applies all the uniforms set for this program object to the Direct3D 9 device
325void Program::applyUniforms()
326{
327 for (unsigned int location = 0; location < mUniforms.size(); location++)
328 {
329 int bytes = mUniforms[location]->bytes;
330 GLfloat *f = (GLfloat*)mUniforms[location]->data;
331 GLint *i = (GLint*)mUniforms[location]->data;
332
333 switch (mUniforms[location]->type)
334 {
335 case UNIFORM_1FV: applyUniform1fv(location, bytes / sizeof(GLfloat), f); break;
336 case UNIFORM_2FV: applyUniform2fv(location, bytes / 2 / sizeof(GLfloat), f); break;
337 case UNIFORM_3FV: applyUniform3fv(location, bytes / 3 / sizeof(GLfloat), f); break;
338 case UNIFORM_4FV: applyUniform4fv(location, bytes / 4 / sizeof(GLfloat), f); break;
339 case UNIFORM_MATRIX_2FV: applyUniformMatrix2fv(location, bytes / 4 / sizeof(GLfloat), f); break;
340 case UNIFORM_MATRIX_3FV: applyUniformMatrix3fv(location, bytes / 9 / sizeof(GLfloat), f); break;
341 case UNIFORM_MATRIX_4FV: applyUniformMatrix4fv(location, bytes / 16 / sizeof(GLfloat), f); break;
342 case UNIFORM_1IV: applyUniform1iv(location, bytes / sizeof(GLint), i); break;
343 default:
344 UNIMPLEMENTED(); // FIXME
345 UNREACHABLE();
346 }
347 }
348}
349
350// Compiles the HLSL code of the attached shaders into executable binaries
351ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
352{
353 if (!hlsl)
354 {
355 return NULL;
356 }
357
358 ID3DXBuffer *binary = NULL;
359 ID3DXBuffer *errorMessage = NULL;
360
361 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, D3DXSHADER_USE_LEGACY_D3DX9_31_DLL, &binary, &errorMessage, constantTable);
362
363 if (SUCCEEDED(result))
364 {
365 return binary;
366 }
367
368 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
369 {
370 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
371 }
372
373 if (errorMessage)
374 {
375 const char *message = (const char*)errorMessage->GetBufferPointer();
376 trace(hlsl);
377 trace(message);
378 }
379
380 return NULL;
381}
382
383// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
384// compiling them into binaries, determining the attribute mappings, and collecting
385// a list of uniforms
386void Program::link()
387{
388 if (mLinked)
389 {
390 return;
391 }
392
393 unlink();
394
395 if (!mFragmentShader || !mFragmentShader->isCompiled())
396 {
397 return;
398 }
399
400 if (!mVertexShader || !mVertexShader->isCompiled())
401 {
402 return;
403 }
404
405 const char *pixelHLSL = mFragmentShader->linkHLSL();
406 const char *vertexHLSL = mVertexShader->linkHLSL(pixelHLSL);
407 ID3DXBuffer *vertexBinary = compileToBinary(vertexHLSL, "vs_2_0", &mConstantTableVS);
408 ID3DXBuffer *pixelBinary = compileToBinary(pixelHLSL, "ps_2_0", &mConstantTablePS);
409
410 if (vertexBinary && pixelBinary)
411 {
412 IDirect3DDevice9 *device = getDevice();
413 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
414 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
415
416 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
417 {
418 return error(GL_OUT_OF_MEMORY);
419 }
420
421 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
422
423 vertexBinary->Release();
424 pixelBinary->Release();
425 vertexBinary = NULL;
426 pixelBinary = NULL;
427
428 if (mVertexExecutable && mPixelExecutable)
429 {
430 if (!linkAttributes())
431 {
432 return;
433 }
434
435 D3DXCONSTANTTABLE_DESC constantTableDescription;
436 D3DXCONSTANT_DESC constantDescription;
437 UINT descriptionCount = 1;
438
439 mConstantTablePS->GetDesc(&constantTableDescription);
440
441 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
442 {
443 D3DXHANDLE constantHandle = mConstantTablePS->GetConstant(0, constantIndex);
444 mConstantTablePS->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
445
446 UniformArray::iterator uniform = mUniforms.begin();
447
448 while (uniform != mUniforms.end())
449 {
450 if ((*uniform)->name == constantDescription.Name)
451 {
452 UNREACHABLE(); // Redefinition; detect at compile
453 }
454
455 uniform++;
456 }
457
458 if (uniform == mUniforms.end())
459 {
460 defineUniform(constantDescription);
461 }
462 }
463
464 mConstantTableVS->GetDesc(&constantTableDescription);
465
466 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
467 {
468 D3DXHANDLE constantHandle = mConstantTableVS->GetConstant(0, constantIndex);
469 mConstantTableVS->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
470
471 UniformArray::iterator uniform = mUniforms.begin();
472
473 while (uniform != mUniforms.end())
474 {
475 if ((*uniform)->name == constantDescription.Name)
476 {
477 UNIMPLEMENTED(); // FIXME: Verify it's the same type as the fragment uniform
478
479 if (true)
480 {
481 break;
482 }
483 else
484 {
485 return;
486 }
487 }
488
489 uniform++;
490 }
491
492 if (uniform == mUniforms.end())
493 {
494 defineUniform(constantDescription);
495 }
496 }
497
498 mLinked = true;
499
500 return;
501 }
502 }
503}
504
505// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
506bool Program::linkAttributes()
507{
508 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
509 {
510 const char *name = mVertexShader->getAttributeName(attributeIndex);
511
512 if (name)
513 {
514 GLuint location = getAttributeLocation(name);
515
516 if (location == -1) // Not set by glBindAttribLocation
517 {
518 int availableIndex = 0;
519
520 while (availableIndex < MAX_VERTEX_ATTRIBS && mAttributeName[availableIndex] && mVertexShader->isActiveAttribute(mAttributeName[availableIndex]))
521 {
522 availableIndex++;
523 }
524
525 if (availableIndex == MAX_VERTEX_ATTRIBS)
526 {
527 return false; // Fail to link
528 }
529
530 delete[] mAttributeName[availableIndex];
531 mAttributeName[availableIndex] = new char[strlen(name) + 1]; // FIXME: Check allocation
532 strcpy(mAttributeName[availableIndex], name);
533 }
534 }
535 }
536
537 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
538 {
539 mInputMapping[attributeIndex] = mVertexShader->getInputMapping(mAttributeName[attributeIndex]);
540 }
541
542 return true;
543}
544
545// Adds the description of a constant found in the binary shader to the list of uniforms
546void Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription)
547{
548 if (constantDescription.Rows == 1) // Vectors and scalars
549 {
550 switch (constantDescription.Type)
551 {
552 case D3DXPT_SAMPLER2D:
553 case D3DXPT_SAMPLERCUBE:
554 case D3DXPT_BOOL:
555 switch (constantDescription.Columns)
556 {
557 case 1:
558 mUniforms.push_back(new Uniform(UNIFORM_1IV, constantDescription.Name, 1 * sizeof(GLint) * constantDescription.Elements));
559 break;
560 default:
561 UNIMPLEMENTED(); // FIXME
562 UNREACHABLE();
563 }
564 break;
565 case D3DXPT_FLOAT:
566 switch (constantDescription.Columns)
567 {
568 case 1:
569 mUniforms.push_back(new Uniform(UNIFORM_1FV, constantDescription.Name, 1 * sizeof(GLfloat) * constantDescription.Elements));
570 break;
571 case 2:
572 mUniforms.push_back(new Uniform(UNIFORM_2FV, constantDescription.Name, 2 * sizeof(GLfloat) * constantDescription.Elements));
573 break;
574 case 3:
575 mUniforms.push_back(new Uniform(UNIFORM_3FV, constantDescription.Name, 3 * sizeof(GLfloat) * constantDescription.Elements));
576 break;
577 case 4:
578 mUniforms.push_back(new Uniform(UNIFORM_4FV, constantDescription.Name, 4 * sizeof(GLfloat) * constantDescription.Elements));
579 break;
580 default: UNREACHABLE();
581 }
582 break;
583 default:
584 UNIMPLEMENTED(); // FIXME
585 UNREACHABLE();
586 }
587 }
588 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
589 {
590 switch (constantDescription.Type)
591 {
592 case D3DXPT_FLOAT:
593 switch (constantDescription.Rows)
594 {
595 case 2:
596 mUniforms.push_back(new Uniform(UNIFORM_MATRIX_2FV, constantDescription.Name, 2 * 2 * sizeof(GLfloat) * constantDescription.Elements));
597 break;
598 case 3:
599 mUniforms.push_back(new Uniform(UNIFORM_MATRIX_3FV, constantDescription.Name, 3 * 3 * sizeof(GLfloat) * constantDescription.Elements));
600 break;
601 case 4:
602 mUniforms.push_back(new Uniform(UNIFORM_MATRIX_4FV, constantDescription.Name, 4 * 4 * sizeof(GLfloat) * constantDescription.Elements));
603 break;
604 default: UNREACHABLE();
605 }
606 break;
607 default: UNREACHABLE();
608 }
609 }
610 else UNREACHABLE();
611}
612
613bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
614{
615 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
616 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
617 IDirect3DDevice9 *device = getDevice();
618
619 if (constantPS)
620 {
621 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
622 }
623
624 if (constantVS)
625 {
626 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
627 }
628
629 return true;
630}
631
632bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
633{
634 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
635
636 for (int i = 0; i < count; i++)
637 {
638 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
639
640 v += 2;
641 }
642
643 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
644 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
645 IDirect3DDevice9 *device = getDevice();
646
647 if (constantPS)
648 {
649 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
650 }
651
652 if (constantVS)
653 {
654 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
655 }
656
657 delete[] vector;
658
659 return true;
660}
661
662bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
663{
664 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
665
666 for (int i = 0; i < count; i++)
667 {
668 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
669
670 v += 3;
671 }
672
673 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
674 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
675 IDirect3DDevice9 *device = getDevice();
676
677 if (constantPS)
678 {
679 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
680 }
681
682 if (constantVS)
683 {
684 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
685 }
686
687 delete[] vector;
688
689 return true;
690}
691
692bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
693{
694 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
695 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
696 IDirect3DDevice9 *device = getDevice();
697
698 if (constantPS)
699 {
700 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
701 }
702
703 if (constantVS)
704 {
705 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
706 }
707
708 return true;
709}
710
711bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
712{
713 D3DXMATRIX *matrix = new D3DXMATRIX[count];
714
715 for (int i = 0; i < count; i++)
716 {
717 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
718 value[1], value[3], 0, 0,
719 0, 0, 1, 0,
720 0, 0, 0, 1);
721
722 value += 4;
723 }
724
725 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
726 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
727 IDirect3DDevice9 *device = getDevice();
728
729 if (constantPS)
730 {
731 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
732 }
733
734 if (constantVS)
735 {
736 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
737 }
738
739 delete[] matrix;
740
741 return true;
742}
743
744bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
745{
746 D3DXMATRIX *matrix = new D3DXMATRIX[count];
747
748 for (int i = 0; i < count; i++)
749 {
750 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
751 value[1], value[4], value[7], 0,
752 value[2], value[5], value[8], 0,
753 0, 0, 0, 1);
754
755 value += 9;
756 }
757
758 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
759 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
760 IDirect3DDevice9 *device = getDevice();
761
762 if (constantPS)
763 {
764 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
765 }
766
767 if (constantVS)
768 {
769 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
770 }
771
772 delete[] matrix;
773
774 return true;
775}
776
777bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
778{
779 D3DXMATRIX *matrix = new D3DXMATRIX[count];
780
781 for (int i = 0; i < count; i++)
782 {
783 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
784 value[1], value[5], value[9], value[13],
785 value[2], value[6], value[10], value[14],
786 value[3], value[7], value[11], value[15]);
787
788 value += 16;
789 }
790
791 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
792 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
793 IDirect3DDevice9 *device = getDevice();
794
795 if (constantPS)
796 {
797 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
798 }
799
800 if (constantVS)
801 {
802 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
803 }
804
805 delete[] matrix;
806
807 return true;
808}
809
810bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
811{
812 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
813 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
814 IDirect3DDevice9 *device = getDevice();
815
816 if (constantPS)
817 {
818 D3DXCONSTANT_DESC constantDescription;
819 UINT descriptionCount = 1;
820 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
821
822 if (SUCCEEDED(result))
823 {
824 return false;
825 }
826
827 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
828 {
829 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
830
831 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
832 {
833 GLint mappedSampler = v[0];
834
835 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
836 {
837 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
838 {
839 mSamplerMapping[samplerIndex] = mappedSampler;
840 }
841 }
842 }
843
844 return true;
845 }
846 }
847
848 if (constantPS)
849 {
850 mConstantTablePS->SetIntArray(device, constantPS, v, count);
851 }
852
853 if (constantVS)
854 {
855 mConstantTableVS->SetIntArray(device, constantVS, v, count);
856 }
857
858 return true;
859}
860
861// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
862void Program::unlink(bool destroy)
863{
864 if (destroy) // Object being destructed
865 {
866 if (mFragmentShader)
867 {
868 mFragmentShader->detach();
869 mFragmentShader = NULL;
870 }
871
872 if (mVertexShader)
873 {
874 mVertexShader->detach();
875 mVertexShader = NULL;
876 }
877
878 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
879 {
880 delete[] mAttributeName[index];
881 mAttributeName[index] = NULL;
882 }
883 }
884
885 if (mPixelExecutable)
886 {
887 mPixelExecutable->Release();
888 mPixelExecutable = NULL;
889 }
890
891 if (mVertexExecutable)
892 {
893 mVertexExecutable->Release();
894 mVertexExecutable = NULL;
895 }
896
897 if (mConstantTablePS)
898 {
899 mConstantTablePS->Release();
900 mConstantTablePS = NULL;
901 }
902
903 if (mConstantTableVS)
904 {
905 mConstantTableVS->Release();
906 mConstantTableVS = NULL;
907 }
908
909 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
910 {
911 mInputMapping[index] = 0;
912 }
913
914 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
915 {
916 mSamplerMapping[index] = 0;
917 }
918
919 while (!mUniforms.empty())
920 {
921 delete mUniforms.back();
922 mUniforms.pop_back();
923 }
924
925 mLinked = false;
926}
927
928bool Program::isLinked()
929{
930 return mLinked;
931}
932
933void Program::flagForDeletion()
934{
935 mDeleteStatus = true;
936}
937
938bool Program::isFlaggedForDeletion() const
939{
940 return mDeleteStatus;
941}
942}