blob: 1d6e36df228c6166144e60c635d793043631b349 [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;
daniel@transgaming.comfbb6dfa2010-03-11 19:41:25 +0000360 DWORD flags = D3DXSHADER_USE_LEGACY_D3DX9_31_DLL |
361 D3DXSHADER_PREFER_FLOW_CONTROL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000362
daniel@transgaming.comfbb6dfa2010-03-11 19:41:25 +0000363 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, flags, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000364
365 if (SUCCEEDED(result))
366 {
367 return binary;
368 }
369
370 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
371 {
372 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
373 }
374
375 if (errorMessage)
376 {
377 const char *message = (const char*)errorMessage->GetBufferPointer();
378 trace(hlsl);
379 trace(message);
380 }
381
382 return NULL;
383}
384
385// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
386// compiling them into binaries, determining the attribute mappings, and collecting
387// a list of uniforms
388void Program::link()
389{
390 if (mLinked)
391 {
392 return;
393 }
394
395 unlink();
396
397 if (!mFragmentShader || !mFragmentShader->isCompiled())
398 {
399 return;
400 }
401
402 if (!mVertexShader || !mVertexShader->isCompiled())
403 {
404 return;
405 }
406
407 const char *pixelHLSL = mFragmentShader->linkHLSL();
408 const char *vertexHLSL = mVertexShader->linkHLSL(pixelHLSL);
daniel@transgaming.comfbb6dfa2010-03-11 19:41:25 +0000409 ID3DXBuffer *vertexBinary = compileToBinary(vertexHLSL, "vs_3_0", &mConstantTableVS);
410 ID3DXBuffer *pixelBinary = compileToBinary(pixelHLSL, "ps_3_0", &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000411
412 if (vertexBinary && pixelBinary)
413 {
414 IDirect3DDevice9 *device = getDevice();
415 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
416 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
417
418 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
419 {
420 return error(GL_OUT_OF_MEMORY);
421 }
422
423 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000424
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000425 vertexBinary->Release();
426 pixelBinary->Release();
427 vertexBinary = NULL;
428 pixelBinary = NULL;
429
430 if (mVertexExecutable && mPixelExecutable)
431 {
432 if (!linkAttributes())
433 {
434 return;
435 }
436
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000437 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000438 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000439 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000440 }
441
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000442 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000443 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000444 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000445 }
446
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000447 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 }
449 }
450}
451
452// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
453bool Program::linkAttributes()
454{
455 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
456 {
457 const char *name = mVertexShader->getAttributeName(attributeIndex);
458
459 if (name)
460 {
461 GLuint location = getAttributeLocation(name);
462
463 if (location == -1) // Not set by glBindAttribLocation
464 {
465 int availableIndex = 0;
466
467 while (availableIndex < MAX_VERTEX_ATTRIBS && mAttributeName[availableIndex] && mVertexShader->isActiveAttribute(mAttributeName[availableIndex]))
468 {
469 availableIndex++;
470 }
471
472 if (availableIndex == MAX_VERTEX_ATTRIBS)
473 {
474 return false; // Fail to link
475 }
476
477 delete[] mAttributeName[availableIndex];
478 mAttributeName[availableIndex] = new char[strlen(name) + 1]; // FIXME: Check allocation
479 strcpy(mAttributeName[availableIndex], name);
480 }
481 }
482 }
483
484 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
485 {
486 mInputMapping[attributeIndex] = mVertexShader->getInputMapping(mAttributeName[attributeIndex]);
487 }
488
489 return true;
490}
491
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000492bool Program::linkUniforms(ID3DXConstantTable *constantTable)
493{
494 D3DXCONSTANTTABLE_DESC constantTableDescription;
495 D3DXCONSTANT_DESC constantDescription;
496 UINT descriptionCount = 1;
497
498 constantTable->GetDesc(&constantTableDescription);
499
500 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
501 {
502 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
503 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
504
505 if (!defineUniform(constantHandle, constantDescription))
506 {
507 return false;
508 }
509 }
510
511 return true;
512}
513
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000514// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000515// Returns true if succesful (uniform not already defined)
516bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
517{
518 switch(constantDescription.Class)
519 {
520 case D3DXPC_STRUCT:
521 {
522 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
523 {
524 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
525
526 D3DXCONSTANT_DESC fieldDescription;
527 UINT descriptionCount = 1;
528
529 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
530
531 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
532 {
533 return false;
534 }
535 }
536
537 return true;
538 }
539 case D3DXPC_SCALAR:
540 case D3DXPC_VECTOR:
541 case D3DXPC_MATRIX_COLUMNS:
542 case D3DXPC_OBJECT:
543 return defineUniform(constantDescription, name + constantDescription.Name);
544 default:
545 UNREACHABLE();
546 return false;
547 }
548}
549
550bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
551{
552 Uniform *uniform = createUniform(constantDescription, name);
553
554 if(!uniform)
555 {
556 return false;
557 }
558
559 // Check if already defined
560 GLint location = getUniformLocation(name.c_str());
561 UniformType type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +0000562
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000563 if (location >= 0)
564 {
565 delete uniform;
566
567 if (mUniforms[location]->type != type)
568 {
569 return false;
570 }
571 else
572 {
573 return true;
574 }
575 }
576
577 mUniforms.push_back(uniform);
578
579 return true;
580}
581
582Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000583{
584 if (constantDescription.Rows == 1) // Vectors and scalars
585 {
586 switch (constantDescription.Type)
587 {
588 case D3DXPT_SAMPLER2D:
589 case D3DXPT_SAMPLERCUBE:
590 case D3DXPT_BOOL:
591 switch (constantDescription.Columns)
592 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000593 case 1: return new Uniform(UNIFORM_1IV, name, 1 * sizeof(GLint) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000594 default:
595 UNIMPLEMENTED(); // FIXME
596 UNREACHABLE();
597 }
598 break;
599 case D3DXPT_FLOAT:
600 switch (constantDescription.Columns)
601 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000602 case 1: return new Uniform(UNIFORM_1FV, name, 1 * sizeof(GLfloat) * constantDescription.Elements);
603 case 2: return new Uniform(UNIFORM_2FV, name, 2 * sizeof(GLfloat) * constantDescription.Elements);
604 case 3: return new Uniform(UNIFORM_3FV, name, 3 * sizeof(GLfloat) * constantDescription.Elements);
605 case 4: return new Uniform(UNIFORM_4FV, name, 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000606 default: UNREACHABLE();
607 }
608 break;
609 default:
610 UNIMPLEMENTED(); // FIXME
611 UNREACHABLE();
612 }
613 }
614 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
615 {
616 switch (constantDescription.Type)
617 {
618 case D3DXPT_FLOAT:
619 switch (constantDescription.Rows)
620 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000621 case 2: return new Uniform(UNIFORM_MATRIX_2FV, name, 2 * 2 * sizeof(GLfloat) * constantDescription.Elements);
622 case 3: return new Uniform(UNIFORM_MATRIX_3FV, name, 3 * 3 * sizeof(GLfloat) * constantDescription.Elements);
623 case 4: return new Uniform(UNIFORM_MATRIX_4FV, name, 4 * 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000624 default: UNREACHABLE();
625 }
626 break;
627 default: UNREACHABLE();
628 }
629 }
630 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000631
632 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000633}
634
635bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
636{
637 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
638 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
639 IDirect3DDevice9 *device = getDevice();
640
641 if (constantPS)
642 {
643 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
644 }
645
646 if (constantVS)
647 {
648 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
649 }
650
651 return true;
652}
653
654bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
655{
656 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
657
658 for (int i = 0; i < count; i++)
659 {
660 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
661
662 v += 2;
663 }
664
665 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
666 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
667 IDirect3DDevice9 *device = getDevice();
668
669 if (constantPS)
670 {
671 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
672 }
673
674 if (constantVS)
675 {
676 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
677 }
678
679 delete[] vector;
680
681 return true;
682}
683
684bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
685{
686 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
687
688 for (int i = 0; i < count; i++)
689 {
690 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
691
692 v += 3;
693 }
694
695 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
696 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
697 IDirect3DDevice9 *device = getDevice();
698
699 if (constantPS)
700 {
701 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
702 }
703
704 if (constantVS)
705 {
706 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
707 }
708
709 delete[] vector;
710
711 return true;
712}
713
714bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
715{
716 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
717 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
718 IDirect3DDevice9 *device = getDevice();
719
720 if (constantPS)
721 {
722 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
723 }
724
725 if (constantVS)
726 {
727 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
728 }
729
730 return true;
731}
732
733bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
734{
735 D3DXMATRIX *matrix = new D3DXMATRIX[count];
736
737 for (int i = 0; i < count; i++)
738 {
739 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
740 value[1], value[3], 0, 0,
741 0, 0, 1, 0,
742 0, 0, 0, 1);
743
744 value += 4;
745 }
746
747 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
748 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
749 IDirect3DDevice9 *device = getDevice();
750
751 if (constantPS)
752 {
753 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
754 }
755
756 if (constantVS)
757 {
758 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
759 }
760
761 delete[] matrix;
762
763 return true;
764}
765
766bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
767{
768 D3DXMATRIX *matrix = new D3DXMATRIX[count];
769
770 for (int i = 0; i < count; i++)
771 {
772 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
773 value[1], value[4], value[7], 0,
774 value[2], value[5], value[8], 0,
775 0, 0, 0, 1);
776
777 value += 9;
778 }
779
780 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
781 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
782 IDirect3DDevice9 *device = getDevice();
783
784 if (constantPS)
785 {
786 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
787 }
788
789 if (constantVS)
790 {
791 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
792 }
793
794 delete[] matrix;
795
796 return true;
797}
798
799bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
800{
801 D3DXMATRIX *matrix = new D3DXMATRIX[count];
802
803 for (int i = 0; i < count; i++)
804 {
805 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
806 value[1], value[5], value[9], value[13],
807 value[2], value[6], value[10], value[14],
808 value[3], value[7], value[11], value[15]);
809
810 value += 16;
811 }
812
813 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
814 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
815 IDirect3DDevice9 *device = getDevice();
816
817 if (constantPS)
818 {
819 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
820 }
821
822 if (constantVS)
823 {
824 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
825 }
826
827 delete[] matrix;
828
829 return true;
830}
831
832bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
833{
834 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
835 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
836 IDirect3DDevice9 *device = getDevice();
837
838 if (constantPS)
839 {
840 D3DXCONSTANT_DESC constantDescription;
841 UINT descriptionCount = 1;
842 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
843
daniel@transgaming.com2884b782010-03-08 21:30:48 +0000844 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000845 {
846 return false;
847 }
848
849 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
850 {
851 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
852
853 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
854 {
855 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000856
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000857 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
858 {
859 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
860 {
861 mSamplerMapping[samplerIndex] = mappedSampler;
862 }
863 }
864 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000865
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000866 return true;
867 }
868 }
869
870 if (constantPS)
871 {
872 mConstantTablePS->SetIntArray(device, constantPS, v, count);
873 }
874
875 if (constantVS)
876 {
877 mConstantTableVS->SetIntArray(device, constantVS, v, count);
878 }
879
880 return true;
881}
882
883// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
884void Program::unlink(bool destroy)
885{
886 if (destroy) // Object being destructed
887 {
888 if (mFragmentShader)
889 {
890 mFragmentShader->detach();
891 mFragmentShader = NULL;
892 }
893
894 if (mVertexShader)
895 {
896 mVertexShader->detach();
897 mVertexShader = NULL;
898 }
899
900 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
901 {
902 delete[] mAttributeName[index];
903 mAttributeName[index] = NULL;
904 }
905 }
906
907 if (mPixelExecutable)
908 {
909 mPixelExecutable->Release();
910 mPixelExecutable = NULL;
911 }
912
913 if (mVertexExecutable)
914 {
915 mVertexExecutable->Release();
916 mVertexExecutable = NULL;
917 }
918
919 if (mConstantTablePS)
920 {
921 mConstantTablePS->Release();
922 mConstantTablePS = NULL;
923 }
924
925 if (mConstantTableVS)
926 {
927 mConstantTableVS->Release();
928 mConstantTableVS = NULL;
929 }
930
931 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
932 {
933 mInputMapping[index] = 0;
934 }
935
936 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
937 {
938 mSamplerMapping[index] = 0;
939 }
940
941 while (!mUniforms.empty())
942 {
943 delete mUniforms.back();
944 mUniforms.pop_back();
945 }
946
947 mLinked = false;
948}
949
950bool Program::isLinked()
951{
952 return mLinked;
953}
954
955void Program::flagForDeletion()
956{
957 mDeleteStatus = true;
958}
959
960bool Program::isFlaggedForDeletion() const
961{
962 return mDeleteStatus;
963}
964}