blob: a9f2f644cd23859304ad3963a4b80026e81bd6be [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"
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000014#include "common/debug.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000015
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();
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000388 TRACE("\n%s", hlsl);
389 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000390 }
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
daniel@transgaming.comdebe2592010-03-24 09:44:08 +0000417 IDirect3DDevice9 *device = getDevice();
418 const char *vertexProfile = D3DXGetVertexShaderProfile(device);
419 const char *pixelProfile = D3DXGetPixelShaderProfile(device);
420
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000421 const char *pixelHLSL = mFragmentShader->linkHLSL();
422 const char *vertexHLSL = mVertexShader->linkHLSL(pixelHLSL);
daniel@transgaming.comdebe2592010-03-24 09:44:08 +0000423 ID3DXBuffer *vertexBinary = compileToBinary(vertexHLSL, vertexProfile, &mConstantTableVS);
424 ID3DXBuffer *pixelBinary = compileToBinary(pixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000425
426 if (vertexBinary && pixelBinary)
427 {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000428 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
429 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
430
431 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
432 {
433 return error(GL_OUT_OF_MEMORY);
434 }
435
436 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000437
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000438 vertexBinary->Release();
439 pixelBinary->Release();
440 vertexBinary = NULL;
441 pixelBinary = NULL;
442
443 if (mVertexExecutable && mPixelExecutable)
444 {
445 if (!linkAttributes())
446 {
447 return;
448 }
449
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000450 for (int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
451 {
452 mSamplers[i].active = false;
453 }
454
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000455 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000456 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000457 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000458 }
459
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000460 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000461 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000462 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000463 }
464
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000465 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000466 }
467 }
468}
469
470// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
471bool Program::linkAttributes()
472{
473 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
474 {
475 const char *name = mVertexShader->getAttributeName(attributeIndex);
476
477 if (name)
478 {
479 GLuint location = getAttributeLocation(name);
480
481 if (location == -1) // Not set by glBindAttribLocation
482 {
483 int availableIndex = 0;
484
485 while (availableIndex < MAX_VERTEX_ATTRIBS && mAttributeName[availableIndex] && mVertexShader->isActiveAttribute(mAttributeName[availableIndex]))
486 {
487 availableIndex++;
488 }
489
490 if (availableIndex == MAX_VERTEX_ATTRIBS)
491 {
492 return false; // Fail to link
493 }
494
495 delete[] mAttributeName[availableIndex];
496 mAttributeName[availableIndex] = new char[strlen(name) + 1]; // FIXME: Check allocation
497 strcpy(mAttributeName[availableIndex], name);
498 }
499 }
500 }
501
502 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
503 {
504 mInputMapping[attributeIndex] = mVertexShader->getInputMapping(mAttributeName[attributeIndex]);
505 }
506
507 return true;
508}
509
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000510bool Program::linkUniforms(ID3DXConstantTable *constantTable)
511{
512 D3DXCONSTANTTABLE_DESC constantTableDescription;
513 D3DXCONSTANT_DESC constantDescription;
514 UINT descriptionCount = 1;
515
516 constantTable->GetDesc(&constantTableDescription);
517
518 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
519 {
520 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
521 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
522
523 if (!defineUniform(constantHandle, constantDescription))
524 {
525 return false;
526 }
527 }
528
529 return true;
530}
531
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000532// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000533// Returns true if succesful (uniform not already defined)
534bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
535{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000536 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
537 {
538 unsigned int samplerIndex = constantDescription.RegisterIndex;
539
540 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
541
542 mSamplers[samplerIndex].active = true;
543 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
544 mSamplers[samplerIndex].logicalTextureUnit = 0;
545 }
546
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000547 switch(constantDescription.Class)
548 {
549 case D3DXPC_STRUCT:
550 {
551 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
552 {
553 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
554
555 D3DXCONSTANT_DESC fieldDescription;
556 UINT descriptionCount = 1;
557
558 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
559
560 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
561 {
562 return false;
563 }
564 }
565
566 return true;
567 }
568 case D3DXPC_SCALAR:
569 case D3DXPC_VECTOR:
570 case D3DXPC_MATRIX_COLUMNS:
571 case D3DXPC_OBJECT:
572 return defineUniform(constantDescription, name + constantDescription.Name);
573 default:
574 UNREACHABLE();
575 return false;
576 }
577}
578
579bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
580{
581 Uniform *uniform = createUniform(constantDescription, name);
582
583 if(!uniform)
584 {
585 return false;
586 }
587
588 // Check if already defined
589 GLint location = getUniformLocation(name.c_str());
590 UniformType type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +0000591
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000592 if (location >= 0)
593 {
594 delete uniform;
595
596 if (mUniforms[location]->type != type)
597 {
598 return false;
599 }
600 else
601 {
602 return true;
603 }
604 }
605
606 mUniforms.push_back(uniform);
607
608 return true;
609}
610
611Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000612{
613 if (constantDescription.Rows == 1) // Vectors and scalars
614 {
615 switch (constantDescription.Type)
616 {
617 case D3DXPT_SAMPLER2D:
618 case D3DXPT_SAMPLERCUBE:
619 case D3DXPT_BOOL:
620 switch (constantDescription.Columns)
621 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000622 case 1: return new Uniform(UNIFORM_1IV, name, 1 * sizeof(GLint) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000623 default:
624 UNIMPLEMENTED(); // FIXME
625 UNREACHABLE();
626 }
627 break;
628 case D3DXPT_FLOAT:
629 switch (constantDescription.Columns)
630 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000631 case 1: return new Uniform(UNIFORM_1FV, name, 1 * sizeof(GLfloat) * constantDescription.Elements);
632 case 2: return new Uniform(UNIFORM_2FV, name, 2 * sizeof(GLfloat) * constantDescription.Elements);
633 case 3: return new Uniform(UNIFORM_3FV, name, 3 * sizeof(GLfloat) * constantDescription.Elements);
634 case 4: return new Uniform(UNIFORM_4FV, name, 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000635 default: UNREACHABLE();
636 }
637 break;
638 default:
639 UNIMPLEMENTED(); // FIXME
640 UNREACHABLE();
641 }
642 }
643 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
644 {
645 switch (constantDescription.Type)
646 {
647 case D3DXPT_FLOAT:
648 switch (constantDescription.Rows)
649 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000650 case 2: return new Uniform(UNIFORM_MATRIX_2FV, name, 2 * 2 * sizeof(GLfloat) * constantDescription.Elements);
651 case 3: return new Uniform(UNIFORM_MATRIX_3FV, name, 3 * 3 * sizeof(GLfloat) * constantDescription.Elements);
652 case 4: return new Uniform(UNIFORM_MATRIX_4FV, name, 4 * 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000653 default: UNREACHABLE();
654 }
655 break;
656 default: UNREACHABLE();
657 }
658 }
659 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000660
661 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000662}
663
664bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
665{
666 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
667 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
668 IDirect3DDevice9 *device = getDevice();
669
670 if (constantPS)
671 {
672 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
673 }
674
675 if (constantVS)
676 {
677 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
678 }
679
680 return true;
681}
682
683bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
684{
685 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
686
687 for (int i = 0; i < count; i++)
688 {
689 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
690
691 v += 2;
692 }
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, vector, count);
701 }
702
703 if (constantVS)
704 {
705 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
706 }
707
708 delete[] vector;
709
710 return true;
711}
712
713bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
714{
715 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
716
717 for (int i = 0; i < count; i++)
718 {
719 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
720
721 v += 3;
722 }
723
724 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
725 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
726 IDirect3DDevice9 *device = getDevice();
727
728 if (constantPS)
729 {
730 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
731 }
732
733 if (constantVS)
734 {
735 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
736 }
737
738 delete[] vector;
739
740 return true;
741}
742
743bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
744{
745 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
746 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
747 IDirect3DDevice9 *device = getDevice();
748
749 if (constantPS)
750 {
751 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
752 }
753
754 if (constantVS)
755 {
756 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
757 }
758
759 return true;
760}
761
762bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
763{
764 D3DXMATRIX *matrix = new D3DXMATRIX[count];
765
766 for (int i = 0; i < count; i++)
767 {
768 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
769 value[1], value[3], 0, 0,
770 0, 0, 1, 0,
771 0, 0, 0, 1);
772
773 value += 4;
774 }
775
776 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
777 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
778 IDirect3DDevice9 *device = getDevice();
779
780 if (constantPS)
781 {
782 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
783 }
784
785 if (constantVS)
786 {
787 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
788 }
789
790 delete[] matrix;
791
792 return true;
793}
794
795bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
796{
797 D3DXMATRIX *matrix = new D3DXMATRIX[count];
798
799 for (int i = 0; i < count; i++)
800 {
801 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
802 value[1], value[4], value[7], 0,
803 value[2], value[5], value[8], 0,
804 0, 0, 0, 1);
805
806 value += 9;
807 }
808
809 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
810 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
811 IDirect3DDevice9 *device = getDevice();
812
813 if (constantPS)
814 {
815 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
816 }
817
818 if (constantVS)
819 {
820 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
821 }
822
823 delete[] matrix;
824
825 return true;
826}
827
828bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
829{
830 D3DXMATRIX *matrix = new D3DXMATRIX[count];
831
832 for (int i = 0; i < count; i++)
833 {
834 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
835 value[1], value[5], value[9], value[13],
836 value[2], value[6], value[10], value[14],
837 value[3], value[7], value[11], value[15]);
838
839 value += 16;
840 }
841
842 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
843 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
844 IDirect3DDevice9 *device = getDevice();
845
846 if (constantPS)
847 {
848 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
849 }
850
851 if (constantVS)
852 {
853 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
854 }
855
856 delete[] matrix;
857
858 return true;
859}
860
861bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
862{
863 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
864 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
865 IDirect3DDevice9 *device = getDevice();
866
867 if (constantPS)
868 {
869 D3DXCONSTANT_DESC constantDescription;
870 UINT descriptionCount = 1;
871 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
872
daniel@transgaming.com2884b782010-03-08 21:30:48 +0000873 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000874 {
875 return false;
876 }
877
878 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
879 {
880 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
881
882 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
883 {
884 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000885
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000886 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
887 {
888 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
889 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000890 ASSERT(mSamplers[samplerIndex].active);
891 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000892 }
893 }
894 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000895
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000896 return true;
897 }
898 }
899
900 if (constantPS)
901 {
902 mConstantTablePS->SetIntArray(device, constantPS, v, count);
903 }
904
905 if (constantVS)
906 {
907 mConstantTableVS->SetIntArray(device, constantVS, v, count);
908 }
909
910 return true;
911}
912
913// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
914void Program::unlink(bool destroy)
915{
916 if (destroy) // Object being destructed
917 {
918 if (mFragmentShader)
919 {
920 mFragmentShader->detach();
921 mFragmentShader = NULL;
922 }
923
924 if (mVertexShader)
925 {
926 mVertexShader->detach();
927 mVertexShader = NULL;
928 }
929
930 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
931 {
932 delete[] mAttributeName[index];
933 mAttributeName[index] = NULL;
934 }
935 }
936
937 if (mPixelExecutable)
938 {
939 mPixelExecutable->Release();
940 mPixelExecutable = NULL;
941 }
942
943 if (mVertexExecutable)
944 {
945 mVertexExecutable->Release();
946 mVertexExecutable = NULL;
947 }
948
949 if (mConstantTablePS)
950 {
951 mConstantTablePS->Release();
952 mConstantTablePS = NULL;
953 }
954
955 if (mConstantTableVS)
956 {
957 mConstantTableVS->Release();
958 mConstantTableVS = NULL;
959 }
960
961 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
962 {
963 mInputMapping[index] = 0;
964 }
965
966 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
967 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000968 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000969 }
970
971 while (!mUniforms.empty())
972 {
973 delete mUniforms.back();
974 mUniforms.pop_back();
975 }
976
977 mLinked = false;
978}
979
980bool Program::isLinked()
981{
982 return mLinked;
983}
984
985void Program::flagForDeletion()
986{
987 mDeleteStatus = true;
988}
989
990bool Program::isFlaggedForDeletion() const
991{
992 return mDeleteStatus;
993}
994}