blob: 7f187314d6ee7d46c4b4e755b387b89c82a95d1a [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{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000167 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
168
169 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000170 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000171 return mSamplers[samplerIndex].logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000172 }
173
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000174 return -1;
175}
176
177SamplerType Program::getSamplerType(unsigned int samplerIndex)
178{
179 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
180 assert(mSamplers[samplerIndex].active);
181
182 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000183}
184
185GLint Program::getUniformLocation(const char *name)
186{
187 for (unsigned int location = 0; location < mUniforms.size(); location++)
188 {
189 if (mUniforms[location]->name == name)
190 {
191 return location;
192 }
193 }
194
195 return -1;
196}
197
198bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
199{
200 if (location < 0 || location >= (int)mUniforms.size())
201 {
202 return false;
203 }
204
205 if (mUniforms[location]->type != UNIFORM_1FV || mUniforms[location]->bytes < sizeof(GLfloat) * count)
206 {
207 return false;
208 }
209
210 memcpy(mUniforms[location]->data, v, sizeof(GLfloat) * count);
211
212 return true;
213}
214
215bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
216{
217 if (location < 0 || location >= (int)mUniforms.size())
218 {
219 return false;
220 }
221
222 if (mUniforms[location]->type != UNIFORM_2FV || mUniforms[location]->bytes < 2 * sizeof(GLfloat) * count)
223 {
224 return false;
225 }
226
227 memcpy(mUniforms[location]->data, v, 2 * sizeof(GLfloat) * count);
228
229 return true;
230}
231
232bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
233{
234 if (location < 0 || location >= (int)mUniforms.size())
235 {
236 return false;
237 }
238
239 if (mUniforms[location]->type != UNIFORM_3FV || mUniforms[location]->bytes < 3 * sizeof(GLfloat) * count)
240 {
241 return false;
242 }
243
244 memcpy(mUniforms[location]->data, v, 3 * sizeof(GLfloat) * count);
245
246 return true;
247}
248
249bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
250{
251 if (location < 0 || location >= (int)mUniforms.size())
252 {
253 return false;
254 }
255
256 if (mUniforms[location]->type != UNIFORM_4FV || mUniforms[location]->bytes < 4 * sizeof(GLfloat) * count)
257 {
258 return false;
259 }
260
261 memcpy(mUniforms[location]->data, v, 4 * sizeof(GLfloat) * count);
262
263 return true;
264}
265
266bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
267{
268 if (location < 0 || location >= (int)mUniforms.size())
269 {
270 return false;
271 }
272
273 if (mUniforms[location]->type != UNIFORM_MATRIX_2FV || mUniforms[location]->bytes < 4 * sizeof(GLfloat) * count)
274 {
275 return false;
276 }
277
278 memcpy(mUniforms[location]->data, value, 4 * sizeof(GLfloat) * count);
279
280 return true;
281}
282
283bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
284{
285 if (location < 0 || location >= (int)mUniforms.size())
286 {
287 return false;
288 }
289
290 if (mUniforms[location]->type != UNIFORM_MATRIX_3FV || mUniforms[location]->bytes < 9 * sizeof(GLfloat) * count)
291 {
292 return false;
293 }
294
295 memcpy(mUniforms[location]->data, value, 9 * sizeof(GLfloat) * count);
296
297 return true;
298}
299
300bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
301{
302 if (location < 0 || location >= (int)mUniforms.size())
303 {
304 return false;
305 }
306
307 if (mUniforms[location]->type != UNIFORM_MATRIX_4FV || mUniforms[location]->bytes < 16 * sizeof(GLfloat) * count)
308 {
309 return false;
310 }
311
312 memcpy(mUniforms[location]->data, value, 16 * sizeof(GLfloat) * count);
313
314 return true;
315}
316
317bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
318{
319 if (location < 0 || location >= (int)mUniforms.size())
320 {
321 return false;
322 }
323
324 if (mUniforms[location]->type != UNIFORM_1IV || mUniforms[location]->bytes < sizeof(GLint) * count)
325 {
326 return false;
327 }
328
329 memcpy(mUniforms[location]->data, v, sizeof(GLint) * count);
330
331 return true;
332}
333
334// Applies all the uniforms set for this program object to the Direct3D 9 device
335void Program::applyUniforms()
336{
337 for (unsigned int location = 0; location < mUniforms.size(); location++)
338 {
339 int bytes = mUniforms[location]->bytes;
340 GLfloat *f = (GLfloat*)mUniforms[location]->data;
341 GLint *i = (GLint*)mUniforms[location]->data;
342
343 switch (mUniforms[location]->type)
344 {
345 case UNIFORM_1FV: applyUniform1fv(location, bytes / sizeof(GLfloat), f); break;
346 case UNIFORM_2FV: applyUniform2fv(location, bytes / 2 / sizeof(GLfloat), f); break;
347 case UNIFORM_3FV: applyUniform3fv(location, bytes / 3 / sizeof(GLfloat), f); break;
348 case UNIFORM_4FV: applyUniform4fv(location, bytes / 4 / sizeof(GLfloat), f); break;
349 case UNIFORM_MATRIX_2FV: applyUniformMatrix2fv(location, bytes / 4 / sizeof(GLfloat), f); break;
350 case UNIFORM_MATRIX_3FV: applyUniformMatrix3fv(location, bytes / 9 / sizeof(GLfloat), f); break;
351 case UNIFORM_MATRIX_4FV: applyUniformMatrix4fv(location, bytes / 16 / sizeof(GLfloat), f); break;
352 case UNIFORM_1IV: applyUniform1iv(location, bytes / sizeof(GLint), i); break;
353 default:
354 UNIMPLEMENTED(); // FIXME
355 UNREACHABLE();
356 }
357 }
358}
359
360// Compiles the HLSL code of the attached shaders into executable binaries
361ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
362{
363 if (!hlsl)
364 {
365 return NULL;
366 }
367
368 ID3DXBuffer *binary = NULL;
369 ID3DXBuffer *errorMessage = NULL;
daniel@transgaming.comfbb6dfa2010-03-11 19:41:25 +0000370 DWORD flags = D3DXSHADER_USE_LEGACY_D3DX9_31_DLL |
371 D3DXSHADER_PREFER_FLOW_CONTROL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000372
daniel@transgaming.comfbb6dfa2010-03-11 19:41:25 +0000373 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, flags, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000374
375 if (SUCCEEDED(result))
376 {
377 return binary;
378 }
379
380 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
381 {
382 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
383 }
384
385 if (errorMessage)
386 {
387 const char *message = (const char*)errorMessage->GetBufferPointer();
388 trace(hlsl);
389 trace(message);
390 }
391
392 return NULL;
393}
394
395// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
396// compiling them into binaries, determining the attribute mappings, and collecting
397// a list of uniforms
398void Program::link()
399{
400 if (mLinked)
401 {
402 return;
403 }
404
405 unlink();
406
407 if (!mFragmentShader || !mFragmentShader->isCompiled())
408 {
409 return;
410 }
411
412 if (!mVertexShader || !mVertexShader->isCompiled())
413 {
414 return;
415 }
416
417 const char *pixelHLSL = mFragmentShader->linkHLSL();
418 const char *vertexHLSL = mVertexShader->linkHLSL(pixelHLSL);
daniel@transgaming.comfbb6dfa2010-03-11 19:41:25 +0000419 ID3DXBuffer *vertexBinary = compileToBinary(vertexHLSL, "vs_3_0", &mConstantTableVS);
420 ID3DXBuffer *pixelBinary = compileToBinary(pixelHLSL, "ps_3_0", &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000421
422 if (vertexBinary && pixelBinary)
423 {
424 IDirect3DDevice9 *device = getDevice();
425 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
426 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
427
428 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
429 {
430 return error(GL_OUT_OF_MEMORY);
431 }
432
433 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000434
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000435 vertexBinary->Release();
436 pixelBinary->Release();
437 vertexBinary = NULL;
438 pixelBinary = NULL;
439
440 if (mVertexExecutable && mPixelExecutable)
441 {
442 if (!linkAttributes())
443 {
444 return;
445 }
446
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000447 for (int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
448 {
449 mSamplers[i].active = false;
450 }
451
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000452 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000453 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000454 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000455 }
456
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000457 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000458 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000459 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000460 }
461
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000462 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000463 }
464 }
465}
466
467// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
468bool Program::linkAttributes()
469{
470 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
471 {
472 const char *name = mVertexShader->getAttributeName(attributeIndex);
473
474 if (name)
475 {
476 GLuint location = getAttributeLocation(name);
477
478 if (location == -1) // Not set by glBindAttribLocation
479 {
480 int availableIndex = 0;
481
482 while (availableIndex < MAX_VERTEX_ATTRIBS && mAttributeName[availableIndex] && mVertexShader->isActiveAttribute(mAttributeName[availableIndex]))
483 {
484 availableIndex++;
485 }
486
487 if (availableIndex == MAX_VERTEX_ATTRIBS)
488 {
489 return false; // Fail to link
490 }
491
492 delete[] mAttributeName[availableIndex];
493 mAttributeName[availableIndex] = new char[strlen(name) + 1]; // FIXME: Check allocation
494 strcpy(mAttributeName[availableIndex], name);
495 }
496 }
497 }
498
499 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
500 {
501 mInputMapping[attributeIndex] = mVertexShader->getInputMapping(mAttributeName[attributeIndex]);
502 }
503
504 return true;
505}
506
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000507bool Program::linkUniforms(ID3DXConstantTable *constantTable)
508{
509 D3DXCONSTANTTABLE_DESC constantTableDescription;
510 D3DXCONSTANT_DESC constantDescription;
511 UINT descriptionCount = 1;
512
513 constantTable->GetDesc(&constantTableDescription);
514
515 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
516 {
517 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
518 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
519
520 if (!defineUniform(constantHandle, constantDescription))
521 {
522 return false;
523 }
524 }
525
526 return true;
527}
528
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000529// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000530// Returns true if succesful (uniform not already defined)
531bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
532{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000533 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
534 {
535 unsigned int samplerIndex = constantDescription.RegisterIndex;
536
537 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
538
539 mSamplers[samplerIndex].active = true;
540 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
541 mSamplers[samplerIndex].logicalTextureUnit = 0;
542 }
543
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000544 switch(constantDescription.Class)
545 {
546 case D3DXPC_STRUCT:
547 {
548 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
549 {
550 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
551
552 D3DXCONSTANT_DESC fieldDescription;
553 UINT descriptionCount = 1;
554
555 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
556
557 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
558 {
559 return false;
560 }
561 }
562
563 return true;
564 }
565 case D3DXPC_SCALAR:
566 case D3DXPC_VECTOR:
567 case D3DXPC_MATRIX_COLUMNS:
568 case D3DXPC_OBJECT:
569 return defineUniform(constantDescription, name + constantDescription.Name);
570 default:
571 UNREACHABLE();
572 return false;
573 }
574}
575
576bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
577{
578 Uniform *uniform = createUniform(constantDescription, name);
579
580 if(!uniform)
581 {
582 return false;
583 }
584
585 // Check if already defined
586 GLint location = getUniformLocation(name.c_str());
587 UniformType type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +0000588
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000589 if (location >= 0)
590 {
591 delete uniform;
592
593 if (mUniforms[location]->type != type)
594 {
595 return false;
596 }
597 else
598 {
599 return true;
600 }
601 }
602
603 mUniforms.push_back(uniform);
604
605 return true;
606}
607
608Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000609{
610 if (constantDescription.Rows == 1) // Vectors and scalars
611 {
612 switch (constantDescription.Type)
613 {
614 case D3DXPT_SAMPLER2D:
615 case D3DXPT_SAMPLERCUBE:
616 case D3DXPT_BOOL:
617 switch (constantDescription.Columns)
618 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000619 case 1: return new Uniform(UNIFORM_1IV, name, 1 * sizeof(GLint) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000620 default:
621 UNIMPLEMENTED(); // FIXME
622 UNREACHABLE();
623 }
624 break;
625 case D3DXPT_FLOAT:
626 switch (constantDescription.Columns)
627 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000628 case 1: return new Uniform(UNIFORM_1FV, name, 1 * sizeof(GLfloat) * constantDescription.Elements);
629 case 2: return new Uniform(UNIFORM_2FV, name, 2 * sizeof(GLfloat) * constantDescription.Elements);
630 case 3: return new Uniform(UNIFORM_3FV, name, 3 * sizeof(GLfloat) * constantDescription.Elements);
631 case 4: return new Uniform(UNIFORM_4FV, name, 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000632 default: UNREACHABLE();
633 }
634 break;
635 default:
636 UNIMPLEMENTED(); // FIXME
637 UNREACHABLE();
638 }
639 }
640 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
641 {
642 switch (constantDescription.Type)
643 {
644 case D3DXPT_FLOAT:
645 switch (constantDescription.Rows)
646 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000647 case 2: return new Uniform(UNIFORM_MATRIX_2FV, name, 2 * 2 * sizeof(GLfloat) * constantDescription.Elements);
648 case 3: return new Uniform(UNIFORM_MATRIX_3FV, name, 3 * 3 * sizeof(GLfloat) * constantDescription.Elements);
649 case 4: return new Uniform(UNIFORM_MATRIX_4FV, name, 4 * 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000650 default: UNREACHABLE();
651 }
652 break;
653 default: UNREACHABLE();
654 }
655 }
656 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000657
658 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000659}
660
661bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
662{
663 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
664 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
665 IDirect3DDevice9 *device = getDevice();
666
667 if (constantPS)
668 {
669 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
670 }
671
672 if (constantVS)
673 {
674 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
675 }
676
677 return true;
678}
679
680bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
681{
682 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
683
684 for (int i = 0; i < count; i++)
685 {
686 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
687
688 v += 2;
689 }
690
691 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
692 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
693 IDirect3DDevice9 *device = getDevice();
694
695 if (constantPS)
696 {
697 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
698 }
699
700 if (constantVS)
701 {
702 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
703 }
704
705 delete[] vector;
706
707 return true;
708}
709
710bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
711{
712 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
713
714 for (int i = 0; i < count; i++)
715 {
716 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
717
718 v += 3;
719 }
720
721 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
722 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
723 IDirect3DDevice9 *device = getDevice();
724
725 if (constantPS)
726 {
727 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
728 }
729
730 if (constantVS)
731 {
732 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
733 }
734
735 delete[] vector;
736
737 return true;
738}
739
740bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
741{
742 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
743 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
744 IDirect3DDevice9 *device = getDevice();
745
746 if (constantPS)
747 {
748 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
749 }
750
751 if (constantVS)
752 {
753 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
754 }
755
756 return true;
757}
758
759bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
760{
761 D3DXMATRIX *matrix = new D3DXMATRIX[count];
762
763 for (int i = 0; i < count; i++)
764 {
765 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
766 value[1], value[3], 0, 0,
767 0, 0, 1, 0,
768 0, 0, 0, 1);
769
770 value += 4;
771 }
772
773 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
774 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
775 IDirect3DDevice9 *device = getDevice();
776
777 if (constantPS)
778 {
779 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
780 }
781
782 if (constantVS)
783 {
784 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
785 }
786
787 delete[] matrix;
788
789 return true;
790}
791
792bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
793{
794 D3DXMATRIX *matrix = new D3DXMATRIX[count];
795
796 for (int i = 0; i < count; i++)
797 {
798 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
799 value[1], value[4], value[7], 0,
800 value[2], value[5], value[8], 0,
801 0, 0, 0, 1);
802
803 value += 9;
804 }
805
806 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
807 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
808 IDirect3DDevice9 *device = getDevice();
809
810 if (constantPS)
811 {
812 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
813 }
814
815 if (constantVS)
816 {
817 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
818 }
819
820 delete[] matrix;
821
822 return true;
823}
824
825bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
826{
827 D3DXMATRIX *matrix = new D3DXMATRIX[count];
828
829 for (int i = 0; i < count; i++)
830 {
831 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
832 value[1], value[5], value[9], value[13],
833 value[2], value[6], value[10], value[14],
834 value[3], value[7], value[11], value[15]);
835
836 value += 16;
837 }
838
839 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
840 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
841 IDirect3DDevice9 *device = getDevice();
842
843 if (constantPS)
844 {
845 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
846 }
847
848 if (constantVS)
849 {
850 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
851 }
852
853 delete[] matrix;
854
855 return true;
856}
857
858bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
859{
860 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
861 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
862 IDirect3DDevice9 *device = getDevice();
863
864 if (constantPS)
865 {
866 D3DXCONSTANT_DESC constantDescription;
867 UINT descriptionCount = 1;
868 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
869
daniel@transgaming.com2884b782010-03-08 21:30:48 +0000870 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000871 {
872 return false;
873 }
874
875 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
876 {
877 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
878
879 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
880 {
881 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000882
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000883 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
884 {
885 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
886 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000887 ASSERT(mSamplers[samplerIndex].active);
888 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000889 }
890 }
891 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000892
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000893 return true;
894 }
895 }
896
897 if (constantPS)
898 {
899 mConstantTablePS->SetIntArray(device, constantPS, v, count);
900 }
901
902 if (constantVS)
903 {
904 mConstantTableVS->SetIntArray(device, constantVS, v, count);
905 }
906
907 return true;
908}
909
910// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
911void Program::unlink(bool destroy)
912{
913 if (destroy) // Object being destructed
914 {
915 if (mFragmentShader)
916 {
917 mFragmentShader->detach();
918 mFragmentShader = NULL;
919 }
920
921 if (mVertexShader)
922 {
923 mVertexShader->detach();
924 mVertexShader = NULL;
925 }
926
927 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
928 {
929 delete[] mAttributeName[index];
930 mAttributeName[index] = NULL;
931 }
932 }
933
934 if (mPixelExecutable)
935 {
936 mPixelExecutable->Release();
937 mPixelExecutable = NULL;
938 }
939
940 if (mVertexExecutable)
941 {
942 mVertexExecutable->Release();
943 mVertexExecutable = NULL;
944 }
945
946 if (mConstantTablePS)
947 {
948 mConstantTablePS->Release();
949 mConstantTablePS = NULL;
950 }
951
952 if (mConstantTableVS)
953 {
954 mConstantTableVS->Release();
955 mConstantTableVS = NULL;
956 }
957
958 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
959 {
960 mInputMapping[index] = 0;
961 }
962
963 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
964 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000965 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000966 }
967
968 while (!mUniforms.empty())
969 {
970 delete mUniforms.back();
971 mUniforms.pop_back();
972 }
973
974 mLinked = false;
975}
976
977bool Program::isLinked()
978{
979 return mLinked;
980}
981
982void Program::flagForDeletion()
983{
984 mDeleteStatus = true;
985}
986
987bool Program::isFlaggedForDeletion() const
988{
989 return mDeleteStatus;
990}
991}