blob: 5686b16a4f63b6fc40987ab53c19cbd7829f7162 [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
daniel@transgaming.comcba50572010-03-28 19:36:09 +000044 mInfoLog = NULL;
45
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000046 unlink();
47
48 mDeleteStatus = false;
49}
50
51Program::~Program()
52{
53 unlink(true);
54}
55
56bool Program::attachShader(Shader *shader)
57{
58 if (shader->getType() == GL_VERTEX_SHADER)
59 {
60 if (mVertexShader)
61 {
62 return false;
63 }
64
65 mVertexShader = (VertexShader*)shader;
66 mVertexShader->attach();
67 }
68 else if (shader->getType() == GL_FRAGMENT_SHADER)
69 {
70 if (mFragmentShader)
71 {
72 return false;
73 }
74
75 mFragmentShader = (FragmentShader*)shader;
76 mFragmentShader->attach();
77 }
78 else UNREACHABLE();
79
80 return true;
81}
82
83bool Program::detachShader(Shader *shader)
84{
85 if (shader->getType() == GL_VERTEX_SHADER)
86 {
87 if (mVertexShader != shader)
88 {
89 return false;
90 }
91
92 mVertexShader->detach();
93 mVertexShader = NULL;
94 }
95 else if (shader->getType() == GL_FRAGMENT_SHADER)
96 {
97 if (mFragmentShader != shader)
98 {
99 return false;
100 }
101
102 mFragmentShader->detach();
103 mFragmentShader = NULL;
104 }
105 else UNREACHABLE();
106
107 unlink();
108
109 return true;
110}
111
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000112int Program::getAttachedShadersCount() const
113{
114 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
115}
116
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000117IDirect3DPixelShader9 *Program::getPixelShader()
118{
119 return mPixelExecutable;
120}
121
122IDirect3DVertexShader9 *Program::getVertexShader()
123{
124 return mVertexExecutable;
125}
126
127void Program::bindAttributeLocation(GLuint index, const char *name)
128{
129 if (index < MAX_VERTEX_ATTRIBS)
130 {
131 delete[] mAttributeName[index];
132 mAttributeName[index] = new char[strlen(name) + 1];
133 strcpy(mAttributeName[index], name);
134 }
135}
136
137GLuint Program::getAttributeLocation(const char *name)
138{
139 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
140 {
141 if (mAttributeName[index] && strcmp(mAttributeName[index], name) == 0)
142 {
143 return index;
144 }
145 }
146
147 return -1;
148}
149
150bool Program::isActiveAttribute(int attributeIndex)
151{
152 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
153 {
154 return mInputMapping[attributeIndex] != -1;
155 }
156
157 return false;
158}
159
160int Program::getInputMapping(int attributeIndex)
161{
162 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
163 {
164 return mInputMapping[attributeIndex];
165 }
166
167 return -1;
168}
169
170// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
171// index referenced in the compiled HLSL shader
172GLint Program::getSamplerMapping(unsigned int samplerIndex)
173{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000174 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
175
176 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000178 return mSamplers[samplerIndex].logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179 }
180
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000181 return -1;
182}
183
184SamplerType Program::getSamplerType(unsigned int samplerIndex)
185{
186 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
187 assert(mSamplers[samplerIndex].active);
188
189 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000190}
191
192GLint Program::getUniformLocation(const char *name)
193{
194 for (unsigned int location = 0; location < mUniforms.size(); location++)
195 {
196 if (mUniforms[location]->name == name)
197 {
198 return location;
199 }
200 }
201
202 return -1;
203}
204
205bool Program::setUniform1fv(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_1FV || mUniforms[location]->bytes < sizeof(GLfloat) * count)
213 {
214 return false;
215 }
216
217 memcpy(mUniforms[location]->data, v, sizeof(GLfloat) * count);
218
219 return true;
220}
221
222bool Program::setUniform2fv(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_2FV || mUniforms[location]->bytes < 2 * sizeof(GLfloat) * count)
230 {
231 return false;
232 }
233
234 memcpy(mUniforms[location]->data, v, 2 * sizeof(GLfloat) * count);
235
236 return true;
237}
238
239bool Program::setUniform3fv(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_3FV || mUniforms[location]->bytes < 3 * sizeof(GLfloat) * count)
247 {
248 return false;
249 }
250
251 memcpy(mUniforms[location]->data, v, 3 * sizeof(GLfloat) * count);
252
253 return true;
254}
255
256bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
257{
258 if (location < 0 || location >= (int)mUniforms.size())
259 {
260 return false;
261 }
262
263 if (mUniforms[location]->type != UNIFORM_4FV || mUniforms[location]->bytes < 4 * sizeof(GLfloat) * count)
264 {
265 return false;
266 }
267
268 memcpy(mUniforms[location]->data, v, 4 * sizeof(GLfloat) * count);
269
270 return true;
271}
272
273bool Program::setUniformMatrix2fv(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_2FV || mUniforms[location]->bytes < 4 * sizeof(GLfloat) * count)
281 {
282 return false;
283 }
284
285 memcpy(mUniforms[location]->data, value, 4 * sizeof(GLfloat) * count);
286
287 return true;
288}
289
290bool Program::setUniformMatrix3fv(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_3FV || mUniforms[location]->bytes < 9 * sizeof(GLfloat) * count)
298 {
299 return false;
300 }
301
302 memcpy(mUniforms[location]->data, value, 9 * sizeof(GLfloat) * count);
303
304 return true;
305}
306
307bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
308{
309 if (location < 0 || location >= (int)mUniforms.size())
310 {
311 return false;
312 }
313
314 if (mUniforms[location]->type != UNIFORM_MATRIX_4FV || mUniforms[location]->bytes < 16 * sizeof(GLfloat) * count)
315 {
316 return false;
317 }
318
319 memcpy(mUniforms[location]->data, value, 16 * sizeof(GLfloat) * count);
320
321 return true;
322}
323
324bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
325{
326 if (location < 0 || location >= (int)mUniforms.size())
327 {
328 return false;
329 }
330
331 if (mUniforms[location]->type != UNIFORM_1IV || mUniforms[location]->bytes < sizeof(GLint) * count)
332 {
333 return false;
334 }
335
336 memcpy(mUniforms[location]->data, v, sizeof(GLint) * count);
337
338 return true;
339}
340
341// Applies all the uniforms set for this program object to the Direct3D 9 device
342void Program::applyUniforms()
343{
344 for (unsigned int location = 0; location < mUniforms.size(); location++)
345 {
346 int bytes = mUniforms[location]->bytes;
347 GLfloat *f = (GLfloat*)mUniforms[location]->data;
348 GLint *i = (GLint*)mUniforms[location]->data;
349
350 switch (mUniforms[location]->type)
351 {
352 case UNIFORM_1FV: applyUniform1fv(location, bytes / sizeof(GLfloat), f); break;
353 case UNIFORM_2FV: applyUniform2fv(location, bytes / 2 / sizeof(GLfloat), f); break;
354 case UNIFORM_3FV: applyUniform3fv(location, bytes / 3 / sizeof(GLfloat), f); break;
355 case UNIFORM_4FV: applyUniform4fv(location, bytes / 4 / sizeof(GLfloat), f); break;
356 case UNIFORM_MATRIX_2FV: applyUniformMatrix2fv(location, bytes / 4 / sizeof(GLfloat), f); break;
357 case UNIFORM_MATRIX_3FV: applyUniformMatrix3fv(location, bytes / 9 / sizeof(GLfloat), f); break;
358 case UNIFORM_MATRIX_4FV: applyUniformMatrix4fv(location, bytes / 16 / sizeof(GLfloat), f); break;
359 case UNIFORM_1IV: applyUniform1iv(location, bytes / sizeof(GLint), i); break;
360 default:
361 UNIMPLEMENTED(); // FIXME
362 UNREACHABLE();
363 }
364 }
365}
366
367// Compiles the HLSL code of the attached shaders into executable binaries
368ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
369{
370 if (!hlsl)
371 {
372 return NULL;
373 }
374
375 ID3DXBuffer *binary = NULL;
376 ID3DXBuffer *errorMessage = NULL;
daniel@transgaming.comfbb6dfa2010-03-11 19:41:25 +0000377 DWORD flags = D3DXSHADER_USE_LEGACY_D3DX9_31_DLL |
378 D3DXSHADER_PREFER_FLOW_CONTROL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000379
daniel@transgaming.comfbb6dfa2010-03-11 19:41:25 +0000380 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, flags, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000381
382 if (SUCCEEDED(result))
383 {
384 return binary;
385 }
386
387 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
388 {
389 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
390 }
391
392 if (errorMessage)
393 {
394 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000395
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000396 TRACE("\n%s", hlsl);
397 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000398 }
399
400 return NULL;
401}
402
403// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
404// compiling them into binaries, determining the attribute mappings, and collecting
405// a list of uniforms
406void Program::link()
407{
408 if (mLinked)
409 {
410 return;
411 }
412
413 unlink();
414
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000415 delete[] mInfoLog;
416 mInfoLog = NULL;
417
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000418 if (!mFragmentShader || !mFragmentShader->isCompiled())
419 {
420 return;
421 }
422
423 if (!mVertexShader || !mVertexShader->isCompiled())
424 {
425 return;
426 }
427
daniel@transgaming.comdebe2592010-03-24 09:44:08 +0000428 IDirect3DDevice9 *device = getDevice();
429 const char *vertexProfile = D3DXGetVertexShaderProfile(device);
430 const char *pixelProfile = D3DXGetPixelShaderProfile(device);
431
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000432 const char *pixelHLSL = mFragmentShader->linkHLSL();
433 const char *vertexHLSL = mVertexShader->linkHLSL(pixelHLSL);
daniel@transgaming.comdebe2592010-03-24 09:44:08 +0000434 ID3DXBuffer *vertexBinary = compileToBinary(vertexHLSL, vertexProfile, &mConstantTableVS);
435 ID3DXBuffer *pixelBinary = compileToBinary(pixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000436
437 if (vertexBinary && pixelBinary)
438 {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000439 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
440 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
441
442 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
443 {
444 return error(GL_OUT_OF_MEMORY);
445 }
446
447 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000448
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000449 vertexBinary->Release();
450 pixelBinary->Release();
451 vertexBinary = NULL;
452 pixelBinary = NULL;
453
454 if (mVertexExecutable && mPixelExecutable)
455 {
456 if (!linkAttributes())
457 {
458 return;
459 }
460
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000461 for (int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
462 {
463 mSamplers[i].active = false;
464 }
465
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000466 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000467 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000468 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000469 }
470
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000471 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000472 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000473 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000474 }
475
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000476 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000477 }
478 }
479}
480
481// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
482bool Program::linkAttributes()
483{
484 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
485 {
486 const char *name = mVertexShader->getAttributeName(attributeIndex);
487
488 if (name)
489 {
490 GLuint location = getAttributeLocation(name);
491
492 if (location == -1) // Not set by glBindAttribLocation
493 {
494 int availableIndex = 0;
495
496 while (availableIndex < MAX_VERTEX_ATTRIBS && mAttributeName[availableIndex] && mVertexShader->isActiveAttribute(mAttributeName[availableIndex]))
497 {
498 availableIndex++;
499 }
500
501 if (availableIndex == MAX_VERTEX_ATTRIBS)
502 {
503 return false; // Fail to link
504 }
505
506 delete[] mAttributeName[availableIndex];
507 mAttributeName[availableIndex] = new char[strlen(name) + 1]; // FIXME: Check allocation
508 strcpy(mAttributeName[availableIndex], name);
509 }
510 }
511 }
512
513 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
514 {
515 mInputMapping[attributeIndex] = mVertexShader->getInputMapping(mAttributeName[attributeIndex]);
516 }
517
518 return true;
519}
520
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000521bool Program::linkUniforms(ID3DXConstantTable *constantTable)
522{
523 D3DXCONSTANTTABLE_DESC constantTableDescription;
524 D3DXCONSTANT_DESC constantDescription;
525 UINT descriptionCount = 1;
526
527 constantTable->GetDesc(&constantTableDescription);
528
529 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
530 {
531 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
532 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
533
534 if (!defineUniform(constantHandle, constantDescription))
535 {
536 return false;
537 }
538 }
539
540 return true;
541}
542
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000543// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000544// Returns true if succesful (uniform not already defined)
545bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
546{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000547 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
548 {
549 unsigned int samplerIndex = constantDescription.RegisterIndex;
550
551 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
552
553 mSamplers[samplerIndex].active = true;
554 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
555 mSamplers[samplerIndex].logicalTextureUnit = 0;
556 }
557
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000558 switch(constantDescription.Class)
559 {
560 case D3DXPC_STRUCT:
561 {
562 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
563 {
564 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
565
566 D3DXCONSTANT_DESC fieldDescription;
567 UINT descriptionCount = 1;
568
569 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
570
571 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
572 {
573 return false;
574 }
575 }
576
577 return true;
578 }
579 case D3DXPC_SCALAR:
580 case D3DXPC_VECTOR:
581 case D3DXPC_MATRIX_COLUMNS:
582 case D3DXPC_OBJECT:
583 return defineUniform(constantDescription, name + constantDescription.Name);
584 default:
585 UNREACHABLE();
586 return false;
587 }
588}
589
590bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
591{
592 Uniform *uniform = createUniform(constantDescription, name);
593
594 if(!uniform)
595 {
596 return false;
597 }
598
599 // Check if already defined
600 GLint location = getUniformLocation(name.c_str());
601 UniformType type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +0000602
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000603 if (location >= 0)
604 {
605 delete uniform;
606
607 if (mUniforms[location]->type != type)
608 {
609 return false;
610 }
611 else
612 {
613 return true;
614 }
615 }
616
617 mUniforms.push_back(uniform);
618
619 return true;
620}
621
622Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000623{
624 if (constantDescription.Rows == 1) // Vectors and scalars
625 {
626 switch (constantDescription.Type)
627 {
628 case D3DXPT_SAMPLER2D:
629 case D3DXPT_SAMPLERCUBE:
630 case D3DXPT_BOOL:
631 switch (constantDescription.Columns)
632 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000633 case 1: return new Uniform(UNIFORM_1IV, name, 1 * sizeof(GLint) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000634 default:
635 UNIMPLEMENTED(); // FIXME
636 UNREACHABLE();
637 }
638 break;
639 case D3DXPT_FLOAT:
640 switch (constantDescription.Columns)
641 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000642 case 1: return new Uniform(UNIFORM_1FV, name, 1 * sizeof(GLfloat) * constantDescription.Elements);
643 case 2: return new Uniform(UNIFORM_2FV, name, 2 * sizeof(GLfloat) * constantDescription.Elements);
644 case 3: return new Uniform(UNIFORM_3FV, name, 3 * sizeof(GLfloat) * constantDescription.Elements);
645 case 4: return new Uniform(UNIFORM_4FV, name, 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000646 default: UNREACHABLE();
647 }
648 break;
649 default:
650 UNIMPLEMENTED(); // FIXME
651 UNREACHABLE();
652 }
653 }
654 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
655 {
656 switch (constantDescription.Type)
657 {
658 case D3DXPT_FLOAT:
659 switch (constantDescription.Rows)
660 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000661 case 2: return new Uniform(UNIFORM_MATRIX_2FV, name, 2 * 2 * sizeof(GLfloat) * constantDescription.Elements);
662 case 3: return new Uniform(UNIFORM_MATRIX_3FV, name, 3 * 3 * sizeof(GLfloat) * constantDescription.Elements);
663 case 4: return new Uniform(UNIFORM_MATRIX_4FV, name, 4 * 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000664 default: UNREACHABLE();
665 }
666 break;
667 default: UNREACHABLE();
668 }
669 }
670 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000671
672 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000673}
674
675bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
676{
677 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
678 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
679 IDirect3DDevice9 *device = getDevice();
680
681 if (constantPS)
682 {
683 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
684 }
685
686 if (constantVS)
687 {
688 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
689 }
690
691 return true;
692}
693
694bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
695{
696 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
697
698 for (int i = 0; i < count; i++)
699 {
700 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
701
702 v += 2;
703 }
704
705 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
706 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
707 IDirect3DDevice9 *device = getDevice();
708
709 if (constantPS)
710 {
711 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
712 }
713
714 if (constantVS)
715 {
716 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
717 }
718
719 delete[] vector;
720
721 return true;
722}
723
724bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
725{
726 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
727
728 for (int i = 0; i < count; i++)
729 {
730 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
731
732 v += 3;
733 }
734
735 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
736 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
737 IDirect3DDevice9 *device = getDevice();
738
739 if (constantPS)
740 {
741 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
742 }
743
744 if (constantVS)
745 {
746 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
747 }
748
749 delete[] vector;
750
751 return true;
752}
753
754bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
755{
756 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
757 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
758 IDirect3DDevice9 *device = getDevice();
759
760 if (constantPS)
761 {
762 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
763 }
764
765 if (constantVS)
766 {
767 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
768 }
769
770 return true;
771}
772
773bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
774{
775 D3DXMATRIX *matrix = new D3DXMATRIX[count];
776
777 for (int i = 0; i < count; i++)
778 {
779 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
780 value[1], value[3], 0, 0,
781 0, 0, 1, 0,
782 0, 0, 0, 1);
783
784 value += 4;
785 }
786
787 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
788 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
789 IDirect3DDevice9 *device = getDevice();
790
791 if (constantPS)
792 {
793 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
794 }
795
796 if (constantVS)
797 {
798 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
799 }
800
801 delete[] matrix;
802
803 return true;
804}
805
806bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
807{
808 D3DXMATRIX *matrix = new D3DXMATRIX[count];
809
810 for (int i = 0; i < count; i++)
811 {
812 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
813 value[1], value[4], value[7], 0,
814 value[2], value[5], value[8], 0,
815 0, 0, 0, 1);
816
817 value += 9;
818 }
819
820 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
821 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
822 IDirect3DDevice9 *device = getDevice();
823
824 if (constantPS)
825 {
826 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
827 }
828
829 if (constantVS)
830 {
831 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
832 }
833
834 delete[] matrix;
835
836 return true;
837}
838
839bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
840{
841 D3DXMATRIX *matrix = new D3DXMATRIX[count];
842
843 for (int i = 0; i < count; i++)
844 {
845 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
846 value[1], value[5], value[9], value[13],
847 value[2], value[6], value[10], value[14],
848 value[3], value[7], value[11], value[15]);
849
850 value += 16;
851 }
852
853 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
854 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
855 IDirect3DDevice9 *device = getDevice();
856
857 if (constantPS)
858 {
859 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
860 }
861
862 if (constantVS)
863 {
864 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
865 }
866
867 delete[] matrix;
868
869 return true;
870}
871
872bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
873{
874 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
875 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
876 IDirect3DDevice9 *device = getDevice();
877
878 if (constantPS)
879 {
880 D3DXCONSTANT_DESC constantDescription;
881 UINT descriptionCount = 1;
882 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
883
daniel@transgaming.com2884b782010-03-08 21:30:48 +0000884 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000885 {
886 return false;
887 }
888
889 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
890 {
891 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
892
893 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
894 {
895 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000896
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000897 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
898 {
899 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
900 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000901 ASSERT(mSamplers[samplerIndex].active);
902 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000903 }
904 }
905 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000906
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000907 return true;
908 }
909 }
910
911 if (constantPS)
912 {
913 mConstantTablePS->SetIntArray(device, constantPS, v, count);
914 }
915
916 if (constantVS)
917 {
918 mConstantTableVS->SetIntArray(device, constantVS, v, count);
919 }
920
921 return true;
922}
923
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000924void Program::appendToInfoLog(const char *info)
925{
926 if (!info)
927 {
928 return;
929 }
930
931 size_t infoLength = strlen(info);
932
933 if (!mInfoLog)
934 {
935 mInfoLog = new char[infoLength + 1];
936 strcpy(mInfoLog, info);
937 }
938 else
939 {
940 size_t logLength = strlen(mInfoLog);
941 char *newLog = new char[logLength + infoLength + 1];
942 strcpy(newLog, mInfoLog);
943 strcpy(newLog + logLength, info);
944
945 delete[] mInfoLog;
946 mInfoLog = newLog;
947 }
948}
949
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000950// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
951void Program::unlink(bool destroy)
952{
953 if (destroy) // Object being destructed
954 {
955 if (mFragmentShader)
956 {
957 mFragmentShader->detach();
958 mFragmentShader = NULL;
959 }
960
961 if (mVertexShader)
962 {
963 mVertexShader->detach();
964 mVertexShader = NULL;
965 }
966
967 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
968 {
969 delete[] mAttributeName[index];
970 mAttributeName[index] = NULL;
971 }
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000972
973 delete[] mInfoLog;
974 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000975 }
976
977 if (mPixelExecutable)
978 {
979 mPixelExecutable->Release();
980 mPixelExecutable = NULL;
981 }
982
983 if (mVertexExecutable)
984 {
985 mVertexExecutable->Release();
986 mVertexExecutable = NULL;
987 }
988
989 if (mConstantTablePS)
990 {
991 mConstantTablePS->Release();
992 mConstantTablePS = NULL;
993 }
994
995 if (mConstantTableVS)
996 {
997 mConstantTableVS->Release();
998 mConstantTableVS = NULL;
999 }
1000
1001 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1002 {
1003 mInputMapping[index] = 0;
1004 }
1005
1006 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
1007 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001008 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001009 }
1010
1011 while (!mUniforms.empty())
1012 {
1013 delete mUniforms.back();
1014 mUniforms.pop_back();
1015 }
1016
1017 mLinked = false;
1018}
1019
1020bool Program::isLinked()
1021{
1022 return mLinked;
1023}
1024
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001025int Program::getInfoLogLength() const
1026{
1027 if (!mInfoLog)
1028 {
1029 return 0;
1030 }
1031 else
1032 {
1033 return strlen(mInfoLog) + 1;
1034 }
1035}
1036
1037void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
1038{
1039 int index = 0;
1040
1041 if (mInfoLog)
1042 {
1043 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
1044 {
1045 infoLog[index] = mInfoLog[index];
1046 index++;
1047 }
1048 }
1049
1050 if (bufSize)
1051 {
1052 infoLog[index] = '\0';
1053 }
1054
1055 if (length)
1056 {
1057 *length = index;
1058 }
1059}
1060
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001061void Program::flagForDeletion()
1062{
1063 mDeleteStatus = true;
1064}
1065
1066bool Program::isFlaggedForDeletion() const
1067{
1068 return mDeleteStatus;
1069}
1070}