blob: 71de7126c1471447785b6fe3fed8d2a41b8f39a3 [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{
daniel@transgaming.com0361b922010-03-28 19:36:15 +000018Uniform::Uniform(GLenum type, const std::string &name, unsigned int bytes) : type(type), name(name), bytes(bytes)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000019{
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
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000212 if (mUniforms[location]->type != GL_FLOAT || mUniforms[location]->bytes < sizeof(GLfloat) * count)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000213 {
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
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000229 if (mUniforms[location]->type != GL_FLOAT_VEC2 || mUniforms[location]->bytes < 2 * sizeof(GLfloat) * count)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000230 {
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
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000246 if (mUniforms[location]->type != GL_FLOAT_VEC3 || mUniforms[location]->bytes < 3 * sizeof(GLfloat) * count)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000247 {
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
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000263 if (mUniforms[location]->type != GL_FLOAT_VEC4 || mUniforms[location]->bytes < 4 * sizeof(GLfloat) * count)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000264 {
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
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000280 if (mUniforms[location]->type != GL_FLOAT_MAT2 || mUniforms[location]->bytes < 4 * sizeof(GLfloat) * count)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000281 {
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
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000297 if (mUniforms[location]->type != GL_FLOAT_MAT3 || mUniforms[location]->bytes < 9 * sizeof(GLfloat) * count)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000298 {
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
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000314 if (mUniforms[location]->type != GL_FLOAT_MAT4 || mUniforms[location]->bytes < 16 * sizeof(GLfloat) * count)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000315 {
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
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000331 if (mUniforms[location]->type != GL_INT || mUniforms[location]->bytes < sizeof(GLint) * count)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000332 {
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 {
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000352 case GL_FLOAT: applyUniform1fv(location, bytes / sizeof(GLfloat), f); break;
353 case GL_FLOAT_VEC2: applyUniform2fv(location, bytes / 2 / sizeof(GLfloat), f); break;
354 case GL_FLOAT_VEC3: applyUniform3fv(location, bytes / 3 / sizeof(GLfloat), f); break;
355 case GL_FLOAT_VEC4: applyUniform4fv(location, bytes / 4 / sizeof(GLfloat), f); break;
356 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, bytes / 4 / sizeof(GLfloat), f); break;
357 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, bytes / 9 / sizeof(GLfloat), f); break;
358 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, bytes / 16 / sizeof(GLfloat), f); break;
359 case GL_INT: applyUniform1iv(location, bytes / sizeof(GLint), i); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000360 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;
377
daniel@transgaming.comcbbca002010-04-01 13:39:32 +0000378 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000379
380 if (SUCCEEDED(result))
381 {
382 return binary;
383 }
384
385 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
386 {
387 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
388 }
389
390 if (errorMessage)
391 {
392 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000393
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000394 TRACE("\n%s", hlsl);
395 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000396 }
397
398 return NULL;
399}
400
401// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
402// compiling them into binaries, determining the attribute mappings, and collecting
403// a list of uniforms
404void Program::link()
405{
406 if (mLinked)
407 {
408 return;
409 }
410
411 unlink();
412
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000413 delete[] mInfoLog;
414 mInfoLog = NULL;
415
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000416 if (!mFragmentShader || !mFragmentShader->isCompiled())
417 {
418 return;
419 }
420
421 if (!mVertexShader || !mVertexShader->isCompiled())
422 {
423 return;
424 }
425
daniel@transgaming.comdebe2592010-03-24 09:44:08 +0000426 IDirect3DDevice9 *device = getDevice();
427 const char *vertexProfile = D3DXGetVertexShaderProfile(device);
428 const char *pixelProfile = D3DXGetPixelShaderProfile(device);
429
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000430 const char *pixelHLSL = mFragmentShader->linkHLSL();
431 const char *vertexHLSL = mVertexShader->linkHLSL(pixelHLSL);
daniel@transgaming.comdebe2592010-03-24 09:44:08 +0000432 ID3DXBuffer *vertexBinary = compileToBinary(vertexHLSL, vertexProfile, &mConstantTableVS);
433 ID3DXBuffer *pixelBinary = compileToBinary(pixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000434
435 if (vertexBinary && pixelBinary)
436 {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000437 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
438 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
439
440 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
441 {
442 return error(GL_OUT_OF_MEMORY);
443 }
444
445 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000446
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000447 vertexBinary->Release();
448 pixelBinary->Release();
449 vertexBinary = NULL;
450 pixelBinary = NULL;
451
452 if (mVertexExecutable && mPixelExecutable)
453 {
454 if (!linkAttributes())
455 {
456 return;
457 }
458
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000459 for (int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
460 {
461 mSamplers[i].active = false;
462 }
463
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000464 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000465 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000466 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000467 }
468
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000469 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000470 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000471 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000472 }
473
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000474 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000475 }
476 }
477}
478
479// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
480bool Program::linkAttributes()
481{
482 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
483 {
484 const char *name = mVertexShader->getAttributeName(attributeIndex);
485
486 if (name)
487 {
488 GLuint location = getAttributeLocation(name);
489
490 if (location == -1) // Not set by glBindAttribLocation
491 {
492 int availableIndex = 0;
493
494 while (availableIndex < MAX_VERTEX_ATTRIBS && mAttributeName[availableIndex] && mVertexShader->isActiveAttribute(mAttributeName[availableIndex]))
495 {
496 availableIndex++;
497 }
498
499 if (availableIndex == MAX_VERTEX_ATTRIBS)
500 {
501 return false; // Fail to link
502 }
503
504 delete[] mAttributeName[availableIndex];
505 mAttributeName[availableIndex] = new char[strlen(name) + 1]; // FIXME: Check allocation
506 strcpy(mAttributeName[availableIndex], name);
507 }
508 }
509 }
510
511 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
512 {
513 mInputMapping[attributeIndex] = mVertexShader->getInputMapping(mAttributeName[attributeIndex]);
514 }
515
516 return true;
517}
518
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000519bool Program::linkUniforms(ID3DXConstantTable *constantTable)
520{
521 D3DXCONSTANTTABLE_DESC constantTableDescription;
522 D3DXCONSTANT_DESC constantDescription;
523 UINT descriptionCount = 1;
524
525 constantTable->GetDesc(&constantTableDescription);
526
527 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
528 {
529 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
530 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
531
532 if (!defineUniform(constantHandle, constantDescription))
533 {
534 return false;
535 }
536 }
537
538 return true;
539}
540
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000541// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000542// Returns true if succesful (uniform not already defined)
543bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
544{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000545 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
546 {
547 unsigned int samplerIndex = constantDescription.RegisterIndex;
548
549 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
550
551 mSamplers[samplerIndex].active = true;
552 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
553 mSamplers[samplerIndex].logicalTextureUnit = 0;
554 }
555
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000556 switch(constantDescription.Class)
557 {
558 case D3DXPC_STRUCT:
559 {
560 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
561 {
562 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
563
564 D3DXCONSTANT_DESC fieldDescription;
565 UINT descriptionCount = 1;
566
567 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
568
569 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
570 {
571 return false;
572 }
573 }
574
575 return true;
576 }
577 case D3DXPC_SCALAR:
578 case D3DXPC_VECTOR:
579 case D3DXPC_MATRIX_COLUMNS:
580 case D3DXPC_OBJECT:
581 return defineUniform(constantDescription, name + constantDescription.Name);
582 default:
583 UNREACHABLE();
584 return false;
585 }
586}
587
588bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
589{
590 Uniform *uniform = createUniform(constantDescription, name);
591
592 if(!uniform)
593 {
594 return false;
595 }
596
597 // Check if already defined
598 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000599 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +0000600
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000601 if (location >= 0)
602 {
603 delete uniform;
604
605 if (mUniforms[location]->type != type)
606 {
607 return false;
608 }
609 else
610 {
611 return true;
612 }
613 }
614
615 mUniforms.push_back(uniform);
616
617 return true;
618}
619
620Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000621{
622 if (constantDescription.Rows == 1) // Vectors and scalars
623 {
624 switch (constantDescription.Type)
625 {
626 case D3DXPT_SAMPLER2D:
627 case D3DXPT_SAMPLERCUBE:
628 case D3DXPT_BOOL:
629 switch (constantDescription.Columns)
630 {
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000631 case 1: return new Uniform(GL_INT, name, 1 * sizeof(GLint) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000632 default:
633 UNIMPLEMENTED(); // FIXME
634 UNREACHABLE();
635 }
636 break;
637 case D3DXPT_FLOAT:
638 switch (constantDescription.Columns)
639 {
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000640 case 1: return new Uniform(GL_FLOAT, name, 1 * sizeof(GLfloat) * constantDescription.Elements);
641 case 2: return new Uniform(GL_FLOAT_VEC2, name, 2 * sizeof(GLfloat) * constantDescription.Elements);
642 case 3: return new Uniform(GL_FLOAT_VEC3, name, 3 * sizeof(GLfloat) * constantDescription.Elements);
643 case 4: return new Uniform(GL_FLOAT_VEC4, name, 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000644 default: UNREACHABLE();
645 }
646 break;
647 default:
648 UNIMPLEMENTED(); // FIXME
649 UNREACHABLE();
650 }
651 }
652 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
653 {
654 switch (constantDescription.Type)
655 {
656 case D3DXPT_FLOAT:
657 switch (constantDescription.Rows)
658 {
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000659 case 2: return new Uniform(GL_FLOAT_MAT2, name, 2 * 2 * sizeof(GLfloat) * constantDescription.Elements);
660 case 3: return new Uniform(GL_FLOAT_MAT3, name, 3 * 3 * sizeof(GLfloat) * constantDescription.Elements);
661 case 4: return new Uniform(GL_FLOAT_MAT4, name, 4 * 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000662 default: UNREACHABLE();
663 }
664 break;
665 default: UNREACHABLE();
666 }
667 }
668 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000669
670 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000671}
672
673bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
674{
675 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
676 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
677 IDirect3DDevice9 *device = getDevice();
678
679 if (constantPS)
680 {
681 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
682 }
683
684 if (constantVS)
685 {
686 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
687 }
688
689 return true;
690}
691
692bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
693{
694 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
695
696 for (int i = 0; i < count; i++)
697 {
698 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
699
700 v += 2;
701 }
702
703 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
704 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
705 IDirect3DDevice9 *device = getDevice();
706
707 if (constantPS)
708 {
709 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
710 }
711
712 if (constantVS)
713 {
714 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
715 }
716
717 delete[] vector;
718
719 return true;
720}
721
722bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
723{
724 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
725
726 for (int i = 0; i < count; i++)
727 {
728 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
729
730 v += 3;
731 }
732
733 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
734 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
735 IDirect3DDevice9 *device = getDevice();
736
737 if (constantPS)
738 {
739 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
740 }
741
742 if (constantVS)
743 {
744 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
745 }
746
747 delete[] vector;
748
749 return true;
750}
751
752bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
753{
754 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
755 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
756 IDirect3DDevice9 *device = getDevice();
757
758 if (constantPS)
759 {
760 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
761 }
762
763 if (constantVS)
764 {
765 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
766 }
767
768 return true;
769}
770
771bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
772{
773 D3DXMATRIX *matrix = new D3DXMATRIX[count];
774
775 for (int i = 0; i < count; i++)
776 {
777 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
778 value[1], value[3], 0, 0,
779 0, 0, 1, 0,
780 0, 0, 0, 1);
781
782 value += 4;
783 }
784
785 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
786 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
787 IDirect3DDevice9 *device = getDevice();
788
789 if (constantPS)
790 {
791 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
792 }
793
794 if (constantVS)
795 {
796 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
797 }
798
799 delete[] matrix;
800
801 return true;
802}
803
804bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
805{
806 D3DXMATRIX *matrix = new D3DXMATRIX[count];
807
808 for (int i = 0; i < count; i++)
809 {
810 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
811 value[1], value[4], value[7], 0,
812 value[2], value[5], value[8], 0,
813 0, 0, 0, 1);
814
815 value += 9;
816 }
817
818 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
819 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
820 IDirect3DDevice9 *device = getDevice();
821
822 if (constantPS)
823 {
824 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
825 }
826
827 if (constantVS)
828 {
829 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
830 }
831
832 delete[] matrix;
833
834 return true;
835}
836
837bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
838{
839 D3DXMATRIX *matrix = new D3DXMATRIX[count];
840
841 for (int i = 0; i < count; i++)
842 {
843 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
844 value[1], value[5], value[9], value[13],
845 value[2], value[6], value[10], value[14],
846 value[3], value[7], value[11], value[15]);
847
848 value += 16;
849 }
850
851 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
852 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
853 IDirect3DDevice9 *device = getDevice();
854
855 if (constantPS)
856 {
857 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
858 }
859
860 if (constantVS)
861 {
862 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
863 }
864
865 delete[] matrix;
866
867 return true;
868}
869
870bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
871{
872 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
873 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
874 IDirect3DDevice9 *device = getDevice();
875
876 if (constantPS)
877 {
878 D3DXCONSTANT_DESC constantDescription;
879 UINT descriptionCount = 1;
880 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
881
daniel@transgaming.com2884b782010-03-08 21:30:48 +0000882 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000883 {
884 return false;
885 }
886
887 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
888 {
889 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
890
891 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
892 {
893 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000894
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000895 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
896 {
897 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
898 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000899 ASSERT(mSamplers[samplerIndex].active);
900 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000901 }
902 }
903 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000904
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000905 return true;
906 }
907 }
908
909 if (constantPS)
910 {
911 mConstantTablePS->SetIntArray(device, constantPS, v, count);
912 }
913
914 if (constantVS)
915 {
916 mConstantTableVS->SetIntArray(device, constantVS, v, count);
917 }
918
919 return true;
920}
921
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000922void Program::appendToInfoLog(const char *info)
923{
924 if (!info)
925 {
926 return;
927 }
928
929 size_t infoLength = strlen(info);
930
931 if (!mInfoLog)
932 {
933 mInfoLog = new char[infoLength + 1];
934 strcpy(mInfoLog, info);
935 }
936 else
937 {
938 size_t logLength = strlen(mInfoLog);
939 char *newLog = new char[logLength + infoLength + 1];
940 strcpy(newLog, mInfoLog);
941 strcpy(newLog + logLength, info);
942
943 delete[] mInfoLog;
944 mInfoLog = newLog;
945 }
946}
947
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000948// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
949void Program::unlink(bool destroy)
950{
951 if (destroy) // Object being destructed
952 {
953 if (mFragmentShader)
954 {
955 mFragmentShader->detach();
956 mFragmentShader = NULL;
957 }
958
959 if (mVertexShader)
960 {
961 mVertexShader->detach();
962 mVertexShader = NULL;
963 }
964
965 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
966 {
967 delete[] mAttributeName[index];
968 mAttributeName[index] = NULL;
969 }
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000970
971 delete[] mInfoLog;
972 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000973 }
974
975 if (mPixelExecutable)
976 {
977 mPixelExecutable->Release();
978 mPixelExecutable = NULL;
979 }
980
981 if (mVertexExecutable)
982 {
983 mVertexExecutable->Release();
984 mVertexExecutable = NULL;
985 }
986
987 if (mConstantTablePS)
988 {
989 mConstantTablePS->Release();
990 mConstantTablePS = NULL;
991 }
992
993 if (mConstantTableVS)
994 {
995 mConstantTableVS->Release();
996 mConstantTableVS = NULL;
997 }
998
999 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1000 {
1001 mInputMapping[index] = 0;
1002 }
1003
1004 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
1005 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001006 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001007 }
1008
1009 while (!mUniforms.empty())
1010 {
1011 delete mUniforms.back();
1012 mUniforms.pop_back();
1013 }
1014
1015 mLinked = false;
1016}
1017
1018bool Program::isLinked()
1019{
1020 return mLinked;
1021}
1022
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001023int Program::getInfoLogLength() const
1024{
1025 if (!mInfoLog)
1026 {
1027 return 0;
1028 }
1029 else
1030 {
1031 return strlen(mInfoLog) + 1;
1032 }
1033}
1034
1035void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
1036{
1037 int index = 0;
1038
1039 if (mInfoLog)
1040 {
1041 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
1042 {
1043 infoLog[index] = mInfoLog[index];
1044 index++;
1045 }
1046 }
1047
1048 if (bufSize)
1049 {
1050 infoLog[index] = '\0';
1051 }
1052
1053 if (length)
1054 {
1055 *length = index;
1056 }
1057}
1058
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001059void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
1060{
1061 int total = 0;
1062
1063 if (mVertexShader)
1064 {
1065 if (total < maxCount)
1066 {
1067 shaders[total] = mVertexShader->getHandle();
1068 }
1069
1070 total++;
1071 }
1072
1073 if (mFragmentShader)
1074 {
1075 if (total < maxCount)
1076 {
1077 shaders[total] = mFragmentShader->getHandle();
1078 }
1079
1080 total++;
1081 }
1082
1083 if (count)
1084 {
1085 *count = total;
1086 }
1087}
1088
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001089void Program::flagForDeletion()
1090{
1091 mDeleteStatus = true;
1092}
1093
1094bool Program::isFlaggedForDeletion() const
1095{
1096 return mDeleteStatus;
1097}
1098}