blob: 3030ac1aca7edcc51e7e9850cb33954449865e58 [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.com296ca9c2010-04-03 20:56:07 +0000426 Context *context = getContext();
427 const char *vertexProfile = context->getVertexShaderProfile();
428 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +0000429
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.com296ca9c2010-04-03 20:56:07 +0000437 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000438 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
439 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
440
441 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
442 {
443 return error(GL_OUT_OF_MEMORY);
444 }
445
446 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000447
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 vertexBinary->Release();
449 pixelBinary->Release();
450 vertexBinary = NULL;
451 pixelBinary = NULL;
452
453 if (mVertexExecutable && mPixelExecutable)
454 {
455 if (!linkAttributes())
456 {
457 return;
458 }
459
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000460 for (int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
461 {
462 mSamplers[i].active = false;
463 }
464
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000465 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000466 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000467 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000468 }
469
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000470 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000471 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000472 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000473 }
474
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000475 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000476 }
477 }
478}
479
480// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
481bool Program::linkAttributes()
482{
483 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
484 {
485 const char *name = mVertexShader->getAttributeName(attributeIndex);
486
487 if (name)
488 {
489 GLuint location = getAttributeLocation(name);
490
491 if (location == -1) // Not set by glBindAttribLocation
492 {
493 int availableIndex = 0;
494
495 while (availableIndex < MAX_VERTEX_ATTRIBS && mAttributeName[availableIndex] && mVertexShader->isActiveAttribute(mAttributeName[availableIndex]))
496 {
497 availableIndex++;
498 }
499
500 if (availableIndex == MAX_VERTEX_ATTRIBS)
501 {
502 return false; // Fail to link
503 }
504
505 delete[] mAttributeName[availableIndex];
506 mAttributeName[availableIndex] = new char[strlen(name) + 1]; // FIXME: Check allocation
507 strcpy(mAttributeName[availableIndex], name);
508 }
509 }
510 }
511
512 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
513 {
514 mInputMapping[attributeIndex] = mVertexShader->getInputMapping(mAttributeName[attributeIndex]);
515 }
516
517 return true;
518}
519
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000520bool Program::linkUniforms(ID3DXConstantTable *constantTable)
521{
522 D3DXCONSTANTTABLE_DESC constantTableDescription;
523 D3DXCONSTANT_DESC constantDescription;
524 UINT descriptionCount = 1;
525
526 constantTable->GetDesc(&constantTableDescription);
527
528 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
529 {
530 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
531 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
532
533 if (!defineUniform(constantHandle, constantDescription))
534 {
535 return false;
536 }
537 }
538
539 return true;
540}
541
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000542// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000543// Returns true if succesful (uniform not already defined)
544bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
545{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000546 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
547 {
548 unsigned int samplerIndex = constantDescription.RegisterIndex;
549
550 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
551
552 mSamplers[samplerIndex].active = true;
553 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
554 mSamplers[samplerIndex].logicalTextureUnit = 0;
555 }
556
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000557 switch(constantDescription.Class)
558 {
559 case D3DXPC_STRUCT:
560 {
561 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
562 {
563 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
564
565 D3DXCONSTANT_DESC fieldDescription;
566 UINT descriptionCount = 1;
567
568 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
569
570 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
571 {
572 return false;
573 }
574 }
575
576 return true;
577 }
578 case D3DXPC_SCALAR:
579 case D3DXPC_VECTOR:
580 case D3DXPC_MATRIX_COLUMNS:
581 case D3DXPC_OBJECT:
582 return defineUniform(constantDescription, name + constantDescription.Name);
583 default:
584 UNREACHABLE();
585 return false;
586 }
587}
588
589bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
590{
591 Uniform *uniform = createUniform(constantDescription, name);
592
593 if(!uniform)
594 {
595 return false;
596 }
597
598 // Check if already defined
599 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000600 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +0000601
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000602 if (location >= 0)
603 {
604 delete uniform;
605
606 if (mUniforms[location]->type != type)
607 {
608 return false;
609 }
610 else
611 {
612 return true;
613 }
614 }
615
616 mUniforms.push_back(uniform);
617
618 return true;
619}
620
621Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000622{
623 if (constantDescription.Rows == 1) // Vectors and scalars
624 {
625 switch (constantDescription.Type)
626 {
627 case D3DXPT_SAMPLER2D:
628 case D3DXPT_SAMPLERCUBE:
629 case D3DXPT_BOOL:
630 switch (constantDescription.Columns)
631 {
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000632 case 1: return new Uniform(GL_INT, name, 1 * sizeof(GLint) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000633 default:
634 UNIMPLEMENTED(); // FIXME
635 UNREACHABLE();
636 }
637 break;
638 case D3DXPT_FLOAT:
639 switch (constantDescription.Columns)
640 {
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000641 case 1: return new Uniform(GL_FLOAT, name, 1 * sizeof(GLfloat) * constantDescription.Elements);
642 case 2: return new Uniform(GL_FLOAT_VEC2, name, 2 * sizeof(GLfloat) * constantDescription.Elements);
643 case 3: return new Uniform(GL_FLOAT_VEC3, name, 3 * sizeof(GLfloat) * constantDescription.Elements);
644 case 4: return new Uniform(GL_FLOAT_VEC4, name, 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000645 default: UNREACHABLE();
646 }
647 break;
648 default:
649 UNIMPLEMENTED(); // FIXME
650 UNREACHABLE();
651 }
652 }
653 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
654 {
655 switch (constantDescription.Type)
656 {
657 case D3DXPT_FLOAT:
658 switch (constantDescription.Rows)
659 {
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000660 case 2: return new Uniform(GL_FLOAT_MAT2, name, 2 * 2 * sizeof(GLfloat) * constantDescription.Elements);
661 case 3: return new Uniform(GL_FLOAT_MAT3, name, 3 * 3 * sizeof(GLfloat) * constantDescription.Elements);
662 case 4: return new Uniform(GL_FLOAT_MAT4, name, 4 * 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000663 default: UNREACHABLE();
664 }
665 break;
666 default: UNREACHABLE();
667 }
668 }
669 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000670
671 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000672}
673
674bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
675{
676 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
677 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
678 IDirect3DDevice9 *device = getDevice();
679
680 if (constantPS)
681 {
682 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
683 }
684
685 if (constantVS)
686 {
687 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
688 }
689
690 return true;
691}
692
693bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
694{
695 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
696
697 for (int i = 0; i < count; i++)
698 {
699 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
700
701 v += 2;
702 }
703
704 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
705 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
706 IDirect3DDevice9 *device = getDevice();
707
708 if (constantPS)
709 {
710 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
711 }
712
713 if (constantVS)
714 {
715 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
716 }
717
718 delete[] vector;
719
720 return true;
721}
722
723bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
724{
725 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
726
727 for (int i = 0; i < count; i++)
728 {
729 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
730
731 v += 3;
732 }
733
734 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
735 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
736 IDirect3DDevice9 *device = getDevice();
737
738 if (constantPS)
739 {
740 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
741 }
742
743 if (constantVS)
744 {
745 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
746 }
747
748 delete[] vector;
749
750 return true;
751}
752
753bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
754{
755 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
756 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
757 IDirect3DDevice9 *device = getDevice();
758
759 if (constantPS)
760 {
761 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
762 }
763
764 if (constantVS)
765 {
766 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
767 }
768
769 return true;
770}
771
772bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
773{
774 D3DXMATRIX *matrix = new D3DXMATRIX[count];
775
776 for (int i = 0; i < count; i++)
777 {
778 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
779 value[1], value[3], 0, 0,
780 0, 0, 1, 0,
781 0, 0, 0, 1);
782
783 value += 4;
784 }
785
786 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
787 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
788 IDirect3DDevice9 *device = getDevice();
789
790 if (constantPS)
791 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +0000792 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000793 }
794
795 if (constantVS)
796 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +0000797 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000798 }
799
800 delete[] matrix;
801
802 return true;
803}
804
805bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
806{
807 D3DXMATRIX *matrix = new D3DXMATRIX[count];
808
809 for (int i = 0; i < count; i++)
810 {
811 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
812 value[1], value[4], value[7], 0,
813 value[2], value[5], value[8], 0,
814 0, 0, 0, 1);
815
816 value += 9;
817 }
818
819 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
820 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
821 IDirect3DDevice9 *device = getDevice();
822
823 if (constantPS)
824 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +0000825 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000826 }
827
828 if (constantVS)
829 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +0000830 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000831 }
832
833 delete[] matrix;
834
835 return true;
836}
837
838bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
839{
840 D3DXMATRIX *matrix = new D3DXMATRIX[count];
841
842 for (int i = 0; i < count; i++)
843 {
844 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
845 value[1], value[5], value[9], value[13],
846 value[2], value[6], value[10], value[14],
847 value[3], value[7], value[11], value[15]);
848
849 value += 16;
850 }
851
852 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
853 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
854 IDirect3DDevice9 *device = getDevice();
855
856 if (constantPS)
857 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +0000858 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000859 }
860
861 if (constantVS)
862 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +0000863 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000864 }
865
866 delete[] matrix;
867
868 return true;
869}
870
871bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
872{
873 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
874 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
875 IDirect3DDevice9 *device = getDevice();
876
877 if (constantPS)
878 {
879 D3DXCONSTANT_DESC constantDescription;
880 UINT descriptionCount = 1;
881 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
882
daniel@transgaming.com2884b782010-03-08 21:30:48 +0000883 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000884 {
885 return false;
886 }
887
888 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
889 {
890 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
891
892 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
893 {
894 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000895
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000896 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
897 {
898 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
899 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000900 ASSERT(mSamplers[samplerIndex].active);
901 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000902 }
903 }
904 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000905
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000906 return true;
907 }
908 }
909
910 if (constantPS)
911 {
912 mConstantTablePS->SetIntArray(device, constantPS, v, count);
913 }
914
915 if (constantVS)
916 {
917 mConstantTableVS->SetIntArray(device, constantVS, v, count);
918 }
919
920 return true;
921}
922
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000923void Program::appendToInfoLog(const char *info)
924{
925 if (!info)
926 {
927 return;
928 }
929
930 size_t infoLength = strlen(info);
931
932 if (!mInfoLog)
933 {
934 mInfoLog = new char[infoLength + 1];
935 strcpy(mInfoLog, info);
936 }
937 else
938 {
939 size_t logLength = strlen(mInfoLog);
940 char *newLog = new char[logLength + infoLength + 1];
941 strcpy(newLog, mInfoLog);
942 strcpy(newLog + logLength, info);
943
944 delete[] mInfoLog;
945 mInfoLog = newLog;
946 }
947}
948
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000949// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
950void Program::unlink(bool destroy)
951{
952 if (destroy) // Object being destructed
953 {
954 if (mFragmentShader)
955 {
956 mFragmentShader->detach();
957 mFragmentShader = NULL;
958 }
959
960 if (mVertexShader)
961 {
962 mVertexShader->detach();
963 mVertexShader = NULL;
964 }
965
966 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
967 {
968 delete[] mAttributeName[index];
969 mAttributeName[index] = NULL;
970 }
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000971
972 delete[] mInfoLog;
973 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000974 }
975
976 if (mPixelExecutable)
977 {
978 mPixelExecutable->Release();
979 mPixelExecutable = NULL;
980 }
981
982 if (mVertexExecutable)
983 {
984 mVertexExecutable->Release();
985 mVertexExecutable = NULL;
986 }
987
988 if (mConstantTablePS)
989 {
990 mConstantTablePS->Release();
991 mConstantTablePS = NULL;
992 }
993
994 if (mConstantTableVS)
995 {
996 mConstantTableVS->Release();
997 mConstantTableVS = NULL;
998 }
999
1000 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1001 {
1002 mInputMapping[index] = 0;
1003 }
1004
1005 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
1006 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001007 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001008 }
1009
1010 while (!mUniforms.empty())
1011 {
1012 delete mUniforms.back();
1013 mUniforms.pop_back();
1014 }
1015
1016 mLinked = false;
1017}
1018
1019bool Program::isLinked()
1020{
1021 return mLinked;
1022}
1023
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001024int Program::getInfoLogLength() const
1025{
1026 if (!mInfoLog)
1027 {
1028 return 0;
1029 }
1030 else
1031 {
1032 return strlen(mInfoLog) + 1;
1033 }
1034}
1035
1036void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
1037{
1038 int index = 0;
1039
1040 if (mInfoLog)
1041 {
1042 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
1043 {
1044 infoLog[index] = mInfoLog[index];
1045 index++;
1046 }
1047 }
1048
1049 if (bufSize)
1050 {
1051 infoLog[index] = '\0';
1052 }
1053
1054 if (length)
1055 {
1056 *length = index;
1057 }
1058}
1059
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001060void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
1061{
1062 int total = 0;
1063
1064 if (mVertexShader)
1065 {
1066 if (total < maxCount)
1067 {
1068 shaders[total] = mVertexShader->getHandle();
1069 }
1070
1071 total++;
1072 }
1073
1074 if (mFragmentShader)
1075 {
1076 if (total < maxCount)
1077 {
1078 shaders[total] = mFragmentShader->getHandle();
1079 }
1080
1081 total++;
1082 }
1083
1084 if (count)
1085 {
1086 *count = total;
1087 }
1088}
1089
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001090void Program::flagForDeletion()
1091{
1092 mDeleteStatus = true;
1093}
1094
1095bool Program::isFlaggedForDeletion() const
1096{
1097 return mDeleteStatus;
1098}
1099}