blob: b0e541e4706b1a8f14b8d6ca3f245b699d6906e7 [file] [log] [blame]
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001//
2// Copyright (c) 2002-2012 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
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000010#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000011#include "libGLESv2/Program.h"
12#include "libGLESv2/ProgramBinary.h"
13
14#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000015#include "common/version.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000016
17#include "libGLESv2/main.h"
18#include "libGLESv2/Shader.h"
19#include "libGLESv2/utilities.h"
20
21#include <string>
22
23#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
24#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3
25#endif
26
27namespace gl
28{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000029std::string str(int i)
30{
31 char buffer[20];
32 snprintf(buffer, sizeof(buffer), "%d", i);
33 return buffer;
34}
35
36Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize)
37 : type(type), _name(_name), name(ProgramBinary::undecorateUniform(_name)), arraySize(arraySize)
38{
39 int bytes = UniformInternalSize(type) * arraySize;
40 data = new unsigned char[bytes];
41 memset(data, 0, bytes);
42 dirty = true;
43}
44
45Uniform::~Uniform()
46{
47 delete[] data;
48}
49
50bool Uniform::isArray()
51{
daniel@transgaming.com22ba0f72012-09-27 17:46:04 +000052 size_t dot = _name.find_last_of('.');
53 if (dot == std::string::npos) dot = -1;
54
55 return _name.compare(dot + 1, dot + 4, "ar_") == 0;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000056}
57
58UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index)
59 : name(ProgramBinary::undecorateUniform(_name)), element(element), index(index)
60{
61}
62
daniel@transgaming.come87ca002012-07-24 18:30:43 +000063unsigned int ProgramBinary::mCurrentSerial = 1;
64
daniel@transgaming.com989c1c82012-07-24 18:40:38 +000065ProgramBinary::ProgramBinary() : RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000066{
daniel@transgaming.come4733d72012-10-31 18:07:01 +000067 mRenderer = getDisplay()->getRenderer();
68 mDevice = mRenderer->getDevice(); // D3D9_REPLACE
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000069
70 mPixelExecutable = NULL;
71 mVertexExecutable = NULL;
72 mConstantTablePS = NULL;
73 mConstantTableVS = NULL;
74
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000075 mValidated = false;
76
77 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
78 {
79 mSemanticIndex[index] = -1;
80 }
81
82 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
83 {
84 mSamplersPS[index].active = false;
85 }
86
87 for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
88 {
89 mSamplersVS[index].active = false;
90 }
91
92 mUsedVertexSamplerRange = 0;
93 mUsedPixelSamplerRange = 0;
94
95 mDxDepthRangeLocation = -1;
96 mDxDepthLocation = -1;
97 mDxCoordLocation = -1;
98 mDxHalfPixelSizeLocation = -1;
99 mDxFrontCCWLocation = -1;
100 mDxPointsOrLinesLocation = -1;
101}
102
103ProgramBinary::~ProgramBinary()
104{
105 if (mPixelExecutable)
106 {
107 mPixelExecutable->Release();
108 }
109
110 if (mVertexExecutable)
111 {
112 mVertexExecutable->Release();
113 }
114
apatrick@chromium.org60dafe82012-09-05 22:26:10 +0000115 delete mConstantTablePS;
116 delete mConstantTableVS;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000117
118 while (!mUniforms.empty())
119 {
120 delete mUniforms.back();
121 mUniforms.pop_back();
122 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000123}
124
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000125unsigned int ProgramBinary::getSerial() const
126{
127 return mSerial;
128}
129
130unsigned int ProgramBinary::issueSerial()
131{
132 return mCurrentSerial++;
133}
134
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000135IDirect3DPixelShader9 *ProgramBinary::getPixelShader()
136{
137 return mPixelExecutable;
138}
139
140IDirect3DVertexShader9 *ProgramBinary::getVertexShader()
141{
142 return mVertexExecutable;
143}
144
145GLuint ProgramBinary::getAttributeLocation(const char *name)
146{
147 if (name)
148 {
149 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
150 {
151 if (mLinkedAttribute[index].name == std::string(name))
152 {
153 return index;
154 }
155 }
156 }
157
158 return -1;
159}
160
161int ProgramBinary::getSemanticIndex(int attributeIndex)
162{
163 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
164
165 return mSemanticIndex[attributeIndex];
166}
167
168// Returns one more than the highest sampler index used.
169GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
170{
171 switch (type)
172 {
173 case SAMPLER_PIXEL:
174 return mUsedPixelSamplerRange;
175 case SAMPLER_VERTEX:
176 return mUsedVertexSamplerRange;
177 default:
178 UNREACHABLE();
179 return 0;
180 }
181}
182
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000183bool ProgramBinary::usesPointSize() const
184{
185 return mUsesPointSize;
186}
187
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000188// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
189// index (0-15 for the pixel shader and 0-3 for the vertex shader).
190GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
191{
192 GLint logicalTextureUnit = -1;
193
194 switch (type)
195 {
196 case SAMPLER_PIXEL:
197 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
198
199 if (mSamplersPS[samplerIndex].active)
200 {
201 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
202 }
203 break;
204 case SAMPLER_VERTEX:
205 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
206
207 if (mSamplersVS[samplerIndex].active)
208 {
209 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
210 }
211 break;
212 default: UNREACHABLE();
213 }
214
215 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)getContext()->getMaximumCombinedTextureImageUnits())
216 {
217 return logicalTextureUnit;
218 }
219
220 return -1;
221}
222
223// Returns the texture type for a given Direct3D 9 sampler type and
224// index (0-15 for the pixel shader and 0-3 for the vertex shader).
225TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
226{
227 switch (type)
228 {
229 case SAMPLER_PIXEL:
230 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
231 ASSERT(mSamplersPS[samplerIndex].active);
232 return mSamplersPS[samplerIndex].textureType;
233 case SAMPLER_VERTEX:
234 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
235 ASSERT(mSamplersVS[samplerIndex].active);
236 return mSamplersVS[samplerIndex].textureType;
237 default: UNREACHABLE();
238 }
239
240 return TEXTURE_2D;
241}
242
243GLint ProgramBinary::getUniformLocation(std::string name)
244{
245 unsigned int subscript = 0;
246
247 // Strip any trailing array operator and retrieve the subscript
248 size_t open = name.find_last_of('[');
249 size_t close = name.find_last_of(']');
250 if (open != std::string::npos && close == name.length() - 1)
251 {
252 subscript = atoi(name.substr(open + 1).c_str());
253 name.erase(open);
254 }
255
256 unsigned int numUniforms = mUniformIndex.size();
257 for (unsigned int location = 0; location < numUniforms; location++)
258 {
259 if (mUniformIndex[location].name == name &&
260 mUniformIndex[location].element == subscript)
261 {
262 return location;
263 }
264 }
265
266 return -1;
267}
268
269bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
270{
271 if (location < 0 || location >= (int)mUniformIndex.size())
272 {
273 return false;
274 }
275
276 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
277 targetUniform->dirty = true;
278
279 if (targetUniform->type == GL_FLOAT)
280 {
281 int arraySize = targetUniform->arraySize;
282
283 if (arraySize == 1 && count > 1)
284 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
285
286 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
287
288 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
289
290 for (int i = 0; i < count; i++)
291 {
292 target[0] = v[0];
293 target[1] = 0;
294 target[2] = 0;
295 target[3] = 0;
296 target += 4;
297 v += 1;
298 }
299 }
300 else if (targetUniform->type == GL_BOOL)
301 {
302 int arraySize = targetUniform->arraySize;
303
304 if (arraySize == 1 && count > 1)
305 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
306
307 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
308 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
309
310 for (int i = 0; i < count; ++i)
311 {
312 if (v[i] == 0.0f)
313 {
314 boolParams[i] = GL_FALSE;
315 }
316 else
317 {
318 boolParams[i] = GL_TRUE;
319 }
320 }
321 }
322 else
323 {
324 return false;
325 }
326
327 return true;
328}
329
330bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
331{
332 if (location < 0 || location >= (int)mUniformIndex.size())
333 {
334 return false;
335 }
336
337 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
338 targetUniform->dirty = true;
339
340 if (targetUniform->type == GL_FLOAT_VEC2)
341 {
342 int arraySize = targetUniform->arraySize;
343
344 if (arraySize == 1 && count > 1)
345 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
346
347 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
348
349 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
350
351 for (int i = 0; i < count; i++)
352 {
353 target[0] = v[0];
354 target[1] = v[1];
355 target[2] = 0;
356 target[3] = 0;
357 target += 4;
358 v += 2;
359 }
360 }
361 else if (targetUniform->type == GL_BOOL_VEC2)
362 {
363 int arraySize = targetUniform->arraySize;
364
365 if (arraySize == 1 && count > 1)
366 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
367
368 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
369
370 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
371
372 for (int i = 0; i < count * 2; ++i)
373 {
374 if (v[i] == 0.0f)
375 {
376 boolParams[i] = GL_FALSE;
377 }
378 else
379 {
380 boolParams[i] = GL_TRUE;
381 }
382 }
383 }
384 else
385 {
386 return false;
387 }
388
389 return true;
390}
391
392bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
393{
394 if (location < 0 || location >= (int)mUniformIndex.size())
395 {
396 return false;
397 }
398
399 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
400 targetUniform->dirty = true;
401
402 if (targetUniform->type == GL_FLOAT_VEC3)
403 {
404 int arraySize = targetUniform->arraySize;
405
406 if (arraySize == 1 && count > 1)
407 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
408
409 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
410
411 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
412
413 for (int i = 0; i < count; i++)
414 {
415 target[0] = v[0];
416 target[1] = v[1];
417 target[2] = v[2];
418 target[3] = 0;
419 target += 4;
420 v += 3;
421 }
422 }
423 else if (targetUniform->type == GL_BOOL_VEC3)
424 {
425 int arraySize = targetUniform->arraySize;
426
427 if (arraySize == 1 && count > 1)
428 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
429
430 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
431 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
432
433 for (int i = 0; i < count * 3; ++i)
434 {
435 if (v[i] == 0.0f)
436 {
437 boolParams[i] = GL_FALSE;
438 }
439 else
440 {
441 boolParams[i] = GL_TRUE;
442 }
443 }
444 }
445 else
446 {
447 return false;
448 }
449
450 return true;
451}
452
453bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
454{
455 if (location < 0 || location >= (int)mUniformIndex.size())
456 {
457 return false;
458 }
459
460 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
461 targetUniform->dirty = true;
462
463 if (targetUniform->type == GL_FLOAT_VEC4)
464 {
465 int arraySize = targetUniform->arraySize;
466
467 if (arraySize == 1 && count > 1)
468 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
469
470 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
471
472 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
473 v, 4 * sizeof(GLfloat) * count);
474 }
475 else if (targetUniform->type == GL_BOOL_VEC4)
476 {
477 int arraySize = targetUniform->arraySize;
478
479 if (arraySize == 1 && count > 1)
480 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
481
482 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
483 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
484
485 for (int i = 0; i < count * 4; ++i)
486 {
487 if (v[i] == 0.0f)
488 {
489 boolParams[i] = GL_FALSE;
490 }
491 else
492 {
493 boolParams[i] = GL_TRUE;
494 }
495 }
496 }
497 else
498 {
499 return false;
500 }
501
502 return true;
503}
504
505template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
506void transposeMatrix(T *target, const GLfloat *value)
507{
508 int copyWidth = std::min(targetWidth, srcWidth);
509 int copyHeight = std::min(targetHeight, srcHeight);
510
511 for (int x = 0; x < copyWidth; x++)
512 {
513 for (int y = 0; y < copyHeight; y++)
514 {
515 target[x * targetWidth + y] = (T)value[y * srcWidth + x];
516 }
517 }
518 // clear unfilled right side
519 for (int y = 0; y < copyHeight; y++)
520 {
521 for (int x = srcWidth; x < targetWidth; x++)
522 {
523 target[y * targetWidth + x] = (T)0;
524 }
525 }
526 // clear unfilled bottom.
527 for (int y = srcHeight; y < targetHeight; y++)
528 {
529 for (int x = 0; x < targetWidth; x++)
530 {
531 target[y * targetWidth + x] = (T)0;
532 }
533 }
534}
535
536bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
537{
538 if (location < 0 || location >= (int)mUniformIndex.size())
539 {
540 return false;
541 }
542
543 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
544 targetUniform->dirty = true;
545
546 if (targetUniform->type != GL_FLOAT_MAT2)
547 {
548 return false;
549 }
550
551 int arraySize = targetUniform->arraySize;
552
553 if (arraySize == 1 && count > 1)
554 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
555
556 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
557
558 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
559 for (int i = 0; i < count; i++)
560 {
561 transposeMatrix<GLfloat,4,2,2,2>(target, value);
562 target += 8;
563 value += 4;
564 }
565
566 return true;
567}
568
569bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
570{
571 if (location < 0 || location >= (int)mUniformIndex.size())
572 {
573 return false;
574 }
575
576 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
577 targetUniform->dirty = true;
578
579 if (targetUniform->type != GL_FLOAT_MAT3)
580 {
581 return false;
582 }
583
584 int arraySize = targetUniform->arraySize;
585
586 if (arraySize == 1 && count > 1)
587 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
588
589 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
590
591 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
592 for (int i = 0; i < count; i++)
593 {
594 transposeMatrix<GLfloat,4,3,3,3>(target, value);
595 target += 12;
596 value += 9;
597 }
598
599 return true;
600}
601
602
603bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
604{
605 if (location < 0 || location >= (int)mUniformIndex.size())
606 {
607 return false;
608 }
609
610 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
611 targetUniform->dirty = true;
612
613 if (targetUniform->type != GL_FLOAT_MAT4)
614 {
615 return false;
616 }
617
618 int arraySize = targetUniform->arraySize;
619
620 if (arraySize == 1 && count > 1)
621 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
622
623 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
624
625 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
626 for (int i = 0; i < count; i++)
627 {
628 transposeMatrix<GLfloat,4,4,4,4>(target, value);
629 target += 16;
630 value += 16;
631 }
632
633 return true;
634}
635
636bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
637{
638 if (location < 0 || location >= (int)mUniformIndex.size())
639 {
640 return false;
641 }
642
643 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
644 targetUniform->dirty = true;
645
646 if (targetUniform->type == GL_INT ||
647 targetUniform->type == GL_SAMPLER_2D ||
648 targetUniform->type == GL_SAMPLER_CUBE)
649 {
650 int arraySize = targetUniform->arraySize;
651
652 if (arraySize == 1 && count > 1)
653 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
654
655 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
656
657 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
658 v, sizeof(GLint) * count);
659 }
660 else if (targetUniform->type == GL_BOOL)
661 {
662 int arraySize = targetUniform->arraySize;
663
664 if (arraySize == 1 && count > 1)
665 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
666
667 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
668 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
669
670 for (int i = 0; i < count; ++i)
671 {
672 if (v[i] == 0)
673 {
674 boolParams[i] = GL_FALSE;
675 }
676 else
677 {
678 boolParams[i] = GL_TRUE;
679 }
680 }
681 }
682 else
683 {
684 return false;
685 }
686
687 return true;
688}
689
690bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
691{
692 if (location < 0 || location >= (int)mUniformIndex.size())
693 {
694 return false;
695 }
696
697 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
698 targetUniform->dirty = true;
699
700 if (targetUniform->type == GL_INT_VEC2)
701 {
702 int arraySize = targetUniform->arraySize;
703
704 if (arraySize == 1 && count > 1)
705 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
706
707 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
708
709 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
710 v, 2 * sizeof(GLint) * count);
711 }
712 else if (targetUniform->type == GL_BOOL_VEC2)
713 {
714 int arraySize = targetUniform->arraySize;
715
716 if (arraySize == 1 && count > 1)
717 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
718
719 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
720 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
721
722 for (int i = 0; i < count * 2; ++i)
723 {
724 if (v[i] == 0)
725 {
726 boolParams[i] = GL_FALSE;
727 }
728 else
729 {
730 boolParams[i] = GL_TRUE;
731 }
732 }
733 }
734 else
735 {
736 return false;
737 }
738
739 return true;
740}
741
742bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
743{
744 if (location < 0 || location >= (int)mUniformIndex.size())
745 {
746 return false;
747 }
748
749 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
750 targetUniform->dirty = true;
751
752 if (targetUniform->type == GL_INT_VEC3)
753 {
754 int arraySize = targetUniform->arraySize;
755
756 if (arraySize == 1 && count > 1)
757 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
758
759 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
760
761 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
762 v, 3 * sizeof(GLint) * count);
763 }
764 else if (targetUniform->type == GL_BOOL_VEC3)
765 {
766 int arraySize = targetUniform->arraySize;
767
768 if (arraySize == 1 && count > 1)
769 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
770
771 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
772 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
773
774 for (int i = 0; i < count * 3; ++i)
775 {
776 if (v[i] == 0)
777 {
778 boolParams[i] = GL_FALSE;
779 }
780 else
781 {
782 boolParams[i] = GL_TRUE;
783 }
784 }
785 }
786 else
787 {
788 return false;
789 }
790
791 return true;
792}
793
794bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
795{
796 if (location < 0 || location >= (int)mUniformIndex.size())
797 {
798 return false;
799 }
800
801 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
802 targetUniform->dirty = true;
803
804 if (targetUniform->type == GL_INT_VEC4)
805 {
806 int arraySize = targetUniform->arraySize;
807
808 if (arraySize == 1 && count > 1)
809 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
810
811 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
812
813 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
814 v, 4 * sizeof(GLint) * count);
815 }
816 else if (targetUniform->type == GL_BOOL_VEC4)
817 {
818 int arraySize = targetUniform->arraySize;
819
820 if (arraySize == 1 && count > 1)
821 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
822
823 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
824 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
825
826 for (int i = 0; i < count * 4; ++i)
827 {
828 if (v[i] == 0)
829 {
830 boolParams[i] = GL_FALSE;
831 }
832 else
833 {
834 boolParams[i] = GL_TRUE;
835 }
836 }
837 }
838 else
839 {
840 return false;
841 }
842
843 return true;
844}
845
846bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
847{
848 if (location < 0 || location >= (int)mUniformIndex.size())
849 {
850 return false;
851 }
852
853 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
854
855 // sized queries -- ensure the provided buffer is large enough
856 if (bufSize)
857 {
858 int requiredBytes = UniformExternalSize(targetUniform->type);
859 if (*bufSize < requiredBytes)
860 {
861 return false;
862 }
863 }
864
865 switch (targetUniform->type)
866 {
867 case GL_FLOAT_MAT2:
868 transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
869 break;
870 case GL_FLOAT_MAT3:
871 transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
872 break;
873 case GL_FLOAT_MAT4:
874 transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
875 break;
876 default:
877 {
878 unsigned int count = UniformExternalComponentCount(targetUniform->type);
879 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
880
881 switch (UniformComponentType(targetUniform->type))
882 {
883 case GL_BOOL:
884 {
885 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * internalCount;
886
887 for (unsigned int i = 0; i < count; ++i)
888 {
889 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
890 }
891 }
892 break;
893 case GL_FLOAT:
894 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLfloat),
895 count * sizeof(GLfloat));
896 break;
897 case GL_INT:
898 {
899 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * internalCount;
900
901 for (unsigned int i = 0; i < count; ++i)
902 {
903 params[i] = (float)intParams[i];
904 }
905 }
906 break;
907 default: UNREACHABLE();
908 }
909 }
910 }
911
912 return true;
913}
914
915bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
916{
917 if (location < 0 || location >= (int)mUniformIndex.size())
918 {
919 return false;
920 }
921
922 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
923
924 // sized queries -- ensure the provided buffer is large enough
925 if (bufSize)
926 {
927 int requiredBytes = UniformExternalSize(targetUniform->type);
928 if (*bufSize < requiredBytes)
929 {
930 return false;
931 }
932 }
933
934 switch (targetUniform->type)
935 {
936 case GL_FLOAT_MAT2:
937 {
938 transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
939 }
940 break;
941 case GL_FLOAT_MAT3:
942 {
943 transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
944 }
945 break;
946 case GL_FLOAT_MAT4:
947 {
948 transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
949 }
950 break;
951 default:
952 {
953 unsigned int count = UniformExternalComponentCount(targetUniform->type);
954 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
955
956 switch (UniformComponentType(targetUniform->type))
957 {
958 case GL_BOOL:
959 {
960 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * internalCount;
961
962 for (unsigned int i = 0; i < count; ++i)
963 {
964 params[i] = (GLint)boolParams[i];
965 }
966 }
967 break;
968 case GL_FLOAT:
969 {
970 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * internalCount;
971
972 for (unsigned int i = 0; i < count; ++i)
973 {
974 params[i] = (GLint)floatParams[i];
975 }
976 }
977 break;
978 case GL_INT:
979 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLint),
980 count * sizeof(GLint));
981 break;
982 default: UNREACHABLE();
983 }
984 }
985 }
986
987 return true;
988}
989
990void ProgramBinary::dirtyAllUniforms()
991{
992 unsigned int numUniforms = mUniforms.size();
993 for (unsigned int index = 0; index < numUniforms; index++)
994 {
995 mUniforms[index]->dirty = true;
996 }
997}
998
999// Applies all the uniforms set for this program object to the Direct3D 9 device
1000void ProgramBinary::applyUniforms()
1001{
1002 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) {
1003 Uniform *targetUniform = *ub;
1004
1005 if (targetUniform->dirty)
1006 {
1007 int arraySize = targetUniform->arraySize;
1008 GLfloat *f = (GLfloat*)targetUniform->data;
1009 GLint *i = (GLint*)targetUniform->data;
1010 GLboolean *b = (GLboolean*)targetUniform->data;
1011
1012 switch (targetUniform->type)
1013 {
1014 case GL_BOOL: applyUniformnbv(targetUniform, arraySize, 1, b); break;
1015 case GL_BOOL_VEC2: applyUniformnbv(targetUniform, arraySize, 2, b); break;
1016 case GL_BOOL_VEC3: applyUniformnbv(targetUniform, arraySize, 3, b); break;
1017 case GL_BOOL_VEC4: applyUniformnbv(targetUniform, arraySize, 4, b); break;
1018 case GL_FLOAT:
1019 case GL_FLOAT_VEC2:
1020 case GL_FLOAT_VEC3:
1021 case GL_FLOAT_VEC4:
1022 case GL_FLOAT_MAT2:
1023 case GL_FLOAT_MAT3:
1024 case GL_FLOAT_MAT4: applyUniformnfv(targetUniform, f); break;
1025 case GL_SAMPLER_2D:
1026 case GL_SAMPLER_CUBE:
1027 case GL_INT: applyUniform1iv(targetUniform, arraySize, i); break;
1028 case GL_INT_VEC2: applyUniform2iv(targetUniform, arraySize, i); break;
1029 case GL_INT_VEC3: applyUniform3iv(targetUniform, arraySize, i); break;
1030 case GL_INT_VEC4: applyUniform4iv(targetUniform, arraySize, i); break;
1031 default:
1032 UNREACHABLE();
1033 }
1034
1035 targetUniform->dirty = false;
1036 }
1037 }
1038}
1039
1040// Compiles the HLSL code of the attached shaders into executable binaries
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001041ID3D10Blob *ProgramBinary::compileToBinary(InfoLog &infoLog, const char *hlsl, const char *profile, D3DConstantTable **constantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001042{
1043 if (!hlsl)
1044 {
1045 return NULL;
1046 }
1047
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001048 DWORD result = NOERROR;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001049 UINT flags = 0;
1050 std::string sourceText;
1051 if (perfActive())
1052 {
1053 flags |= D3DCOMPILE_DEBUG;
1054#ifdef NDEBUG
1055 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1056#else
1057 flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
1058#endif
1059
1060 std::string sourcePath = getTempPath();
1061 sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
1062 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
1063 }
1064 else
1065 {
1066 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1067 sourceText = hlsl;
1068 }
1069
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001070 // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options.
1071 // Try the default flags first and if compilation fails, try some alternatives.
1072 const static UINT extraFlags[] =
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001073 {
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001074 0,
1075 D3DCOMPILE_AVOID_FLOW_CONTROL,
1076 D3DCOMPILE_PREFER_FLOW_CONTROL
1077 };
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001078
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001079 const static char * const extraFlagNames[] =
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001080 {
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001081 "default",
1082 "avoid flow control",
1083 "prefer flow control"
1084 };
1085
1086 for (int i = 0; i < sizeof(extraFlags) / sizeof(UINT); ++i)
1087 {
1088 ID3D10Blob *errorMessage = NULL;
1089 ID3D10Blob *binary = NULL;
1090 result = D3DCompile(hlsl, strlen(hlsl), g_fakepath, NULL, NULL, "main", profile, flags | extraFlags[i], 0, &binary, &errorMessage);
1091
1092 if (errorMessage)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001093 {
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001094 const char *message = (const char*)errorMessage->GetBufferPointer();
1095
1096 infoLog.appendSanitized(message);
1097 TRACE("\n%s", hlsl);
1098 TRACE("\n%s", message);
1099
1100 errorMessage->Release();
1101 errorMessage = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001102 }
1103
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001104 if (SUCCEEDED(result))
1105 {
1106 D3DConstantTable *table = new D3DConstantTable(binary->GetBufferPointer(), binary->GetBufferSize());
1107 if (table->error())
1108 {
1109 delete table;
1110 binary->Release();
1111 return NULL;
1112 }
1113
1114 *constantTable = table;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001115
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001116 return binary;
1117 }
1118 else
1119 {
1120 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1121 {
1122 return error(GL_OUT_OF_MEMORY, (ID3D10Blob*) NULL);
1123 }
1124
1125 infoLog.append("Warning: D3D shader compilation failed with ");
1126 infoLog.append(extraFlagNames[i]);
1127 infoLog.append(" flags.");
1128 if (i + 1 < sizeof(extraFlagNames) / sizeof(char*))
1129 {
1130 infoLog.append(" Retrying with ");
1131 infoLog.append(extraFlagNames[i + 1]);
1132 infoLog.append(".\n");
1133 }
1134 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001135 }
1136
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001137 return NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001138}
1139
1140// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1141// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001142int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001143{
1144 Context *context = getContext();
1145 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1146
1147 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1148 {
1149 int n = VariableRowCount(varying->type) * varying->size;
1150 int m = VariableColumnCount(varying->type);
1151 bool success = false;
1152
1153 if (m == 2 || m == 3 || m == 4)
1154 {
1155 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
1156 {
1157 bool available = true;
1158
1159 for (int y = 0; y < n && available; y++)
1160 {
1161 for (int x = 0; x < m && available; x++)
1162 {
1163 if (packing[r + y][x])
1164 {
1165 available = false;
1166 }
1167 }
1168 }
1169
1170 if (available)
1171 {
1172 varying->reg = r;
1173 varying->col = 0;
1174
1175 for (int y = 0; y < n; y++)
1176 {
1177 for (int x = 0; x < m; x++)
1178 {
1179 packing[r + y][x] = &*varying;
1180 }
1181 }
1182
1183 success = true;
1184 }
1185 }
1186
1187 if (!success && m == 2)
1188 {
1189 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
1190 {
1191 bool available = true;
1192
1193 for (int y = 0; y < n && available; y++)
1194 {
1195 for (int x = 2; x < 4 && available; x++)
1196 {
1197 if (packing[r + y][x])
1198 {
1199 available = false;
1200 }
1201 }
1202 }
1203
1204 if (available)
1205 {
1206 varying->reg = r;
1207 varying->col = 2;
1208
1209 for (int y = 0; y < n; y++)
1210 {
1211 for (int x = 2; x < 4; x++)
1212 {
1213 packing[r + y][x] = &*varying;
1214 }
1215 }
1216
1217 success = true;
1218 }
1219 }
1220 }
1221 }
1222 else if (m == 1)
1223 {
1224 int space[4] = {0};
1225
1226 for (int y = 0; y < maxVaryingVectors; y++)
1227 {
1228 for (int x = 0; x < 4; x++)
1229 {
1230 space[x] += packing[y][x] ? 0 : 1;
1231 }
1232 }
1233
1234 int column = 0;
1235
1236 for (int x = 0; x < 4; x++)
1237 {
1238 if (space[x] >= n && space[x] < space[column])
1239 {
1240 column = x;
1241 }
1242 }
1243
1244 if (space[column] >= n)
1245 {
1246 for (int r = 0; r < maxVaryingVectors; r++)
1247 {
1248 if (!packing[r][column])
1249 {
1250 varying->reg = r;
1251
1252 for (int y = r; y < r + n; y++)
1253 {
1254 packing[y][column] = &*varying;
1255 }
1256
1257 break;
1258 }
1259 }
1260
1261 varying->col = column;
1262
1263 success = true;
1264 }
1265 }
1266 else UNREACHABLE();
1267
1268 if (!success)
1269 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001270 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001271
1272 return -1;
1273 }
1274 }
1275
1276 // Return the number of used registers
1277 int registers = 0;
1278
1279 for (int r = 0; r < maxVaryingVectors; r++)
1280 {
1281 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1282 {
1283 registers++;
1284 }
1285 }
1286
1287 return registers;
1288}
1289
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001290bool ProgramBinary::linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001291{
1292 if (pixelHLSL.empty() || vertexHLSL.empty())
1293 {
1294 return false;
1295 }
1296
1297 // Reset the varying register assignments
1298 for (VaryingList::iterator fragVar = fragmentShader->mVaryings.begin(); fragVar != fragmentShader->mVaryings.end(); fragVar++)
1299 {
1300 fragVar->reg = -1;
1301 fragVar->col = -1;
1302 }
1303
1304 for (VaryingList::iterator vtxVar = vertexShader->mVaryings.begin(); vtxVar != vertexShader->mVaryings.end(); vtxVar++)
1305 {
1306 vtxVar->reg = -1;
1307 vtxVar->col = -1;
1308 }
1309
1310 // Map the varyings to the register file
1311 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001312 int registers = packVaryings(infoLog, packing, fragmentShader);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001313
1314 if (registers < 0)
1315 {
1316 return false;
1317 }
1318
1319 // Write the HLSL input/output declarations
1320 Context *context = getContext();
1321 const bool sm3 = context->supportsShaderModel3();
1322 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1323
1324 if (registers == maxVaryingVectors && fragmentShader->mUsesFragCoord)
1325 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001326 infoLog.append("No varying registers left to support gl_FragCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001327
1328 return false;
1329 }
1330
1331 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1332 {
1333 bool matched = false;
1334
1335 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1336 {
1337 if (output->name == input->name)
1338 {
1339 if (output->type != input->type || output->size != input->size)
1340 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001341 infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001342
1343 return false;
1344 }
1345
1346 output->reg = input->reg;
1347 output->col = input->col;
1348
1349 matched = true;
1350 break;
1351 }
1352 }
1353
1354 if (!matched)
1355 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001356 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001357
1358 return false;
1359 }
1360 }
1361
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001362 mUsesPointSize = vertexShader->mUsesPointSize;
1363 std::string varyingSemantic = (mUsesPointSize && sm3) ? "COLOR" : "TEXCOORD";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001364
1365 vertexHLSL += "struct VS_INPUT\n"
1366 "{\n";
1367
1368 int semanticIndex = 0;
1369 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1370 {
1371 switch (attribute->type)
1372 {
1373 case GL_FLOAT: vertexHLSL += " float "; break;
1374 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1375 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1376 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1377 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1378 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1379 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1380 default: UNREACHABLE();
1381 }
1382
1383 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1384
1385 semanticIndex += VariableRowCount(attribute->type);
1386 }
1387
1388 vertexHLSL += "};\n"
1389 "\n"
1390 "struct VS_OUTPUT\n"
1391 "{\n"
1392 " float4 gl_Position : POSITION;\n";
1393
1394 for (int r = 0; r < registers; r++)
1395 {
1396 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1397
1398 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1399 }
1400
1401 if (fragmentShader->mUsesFragCoord)
1402 {
1403 vertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1404 }
1405
1406 if (vertexShader->mUsesPointSize && sm3)
1407 {
1408 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1409 }
1410
1411 vertexHLSL += "};\n"
1412 "\n"
1413 "VS_OUTPUT main(VS_INPUT input)\n"
1414 "{\n";
1415
1416 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1417 {
1418 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1419
1420 if (VariableRowCount(attribute->type) > 1) // Matrix
1421 {
1422 vertexHLSL += "transpose";
1423 }
1424
1425 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1426 }
1427
1428 vertexHLSL += "\n"
1429 " gl_main();\n"
1430 "\n"
1431 " VS_OUTPUT output;\n"
1432 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001433 " output.gl_Position.y = -(gl_Position.y + dx_HalfPixelSize.y * gl_Position.w);\n"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001434 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1435 " output.gl_Position.w = gl_Position.w;\n";
1436
1437 if (vertexShader->mUsesPointSize && sm3)
1438 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001439 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001440 }
1441
1442 if (fragmentShader->mUsesFragCoord)
1443 {
1444 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1445 }
1446
1447 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1448 {
1449 if (varying->reg >= 0)
1450 {
1451 for (int i = 0; i < varying->size; i++)
1452 {
1453 int rows = VariableRowCount(varying->type);
1454
1455 for (int j = 0; j < rows; j++)
1456 {
1457 int r = varying->reg + i * rows + j;
1458 vertexHLSL += " output.v" + str(r);
1459
1460 bool sharedRegister = false; // Register used by multiple varyings
1461
1462 for (int x = 0; x < 4; x++)
1463 {
1464 if (packing[r][x] && packing[r][x] != packing[r][0])
1465 {
1466 sharedRegister = true;
1467 break;
1468 }
1469 }
1470
1471 if(sharedRegister)
1472 {
1473 vertexHLSL += ".";
1474
1475 for (int x = 0; x < 4; x++)
1476 {
1477 if (packing[r][x] == &*varying)
1478 {
1479 switch(x)
1480 {
1481 case 0: vertexHLSL += "x"; break;
1482 case 1: vertexHLSL += "y"; break;
1483 case 2: vertexHLSL += "z"; break;
1484 case 3: vertexHLSL += "w"; break;
1485 }
1486 }
1487 }
1488 }
1489
1490 vertexHLSL += " = " + varying->name;
1491
1492 if (varying->array)
1493 {
1494 vertexHLSL += "[" + str(i) + "]";
1495 }
1496
1497 if (rows > 1)
1498 {
1499 vertexHLSL += "[" + str(j) + "]";
1500 }
1501
1502 vertexHLSL += ";\n";
1503 }
1504 }
1505 }
1506 }
1507
1508 vertexHLSL += "\n"
1509 " return output;\n"
1510 "}\n";
1511
1512 pixelHLSL += "struct PS_INPUT\n"
1513 "{\n";
1514
1515 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1516 {
1517 if (varying->reg >= 0)
1518 {
1519 for (int i = 0; i < varying->size; i++)
1520 {
1521 int rows = VariableRowCount(varying->type);
1522 for (int j = 0; j < rows; j++)
1523 {
1524 std::string n = str(varying->reg + i * rows + j);
1525 pixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
1526 }
1527 }
1528 }
1529 else UNREACHABLE();
1530 }
1531
1532 if (fragmentShader->mUsesFragCoord)
1533 {
1534 pixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1535 if (sm3) {
1536 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1537 }
1538 }
1539
1540 if (fragmentShader->mUsesPointCoord && sm3)
1541 {
1542 pixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1543 }
1544
1545 if (fragmentShader->mUsesFrontFacing)
1546 {
1547 pixelHLSL += " float vFace : VFACE;\n";
1548 }
1549
1550 pixelHLSL += "};\n"
1551 "\n"
1552 "struct PS_OUTPUT\n"
1553 "{\n"
1554 " float4 gl_Color[1] : COLOR;\n"
1555 "};\n"
1556 "\n"
1557 "PS_OUTPUT main(PS_INPUT input)\n"
1558 "{\n";
1559
1560 if (fragmentShader->mUsesFragCoord)
1561 {
1562 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1563
1564 if (sm3)
1565 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001566 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001567 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001568 }
1569 else
1570 {
1571 // dx_Coord contains the viewport width/2, height/2, center.x and center.y. See Context::applyRenderTarget()
1572 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Coord.x + dx_Coord.z;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001573 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Coord.y + dx_Coord.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001574 }
1575
1576 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
1577 " gl_FragCoord.w = rhw;\n";
1578 }
1579
1580 if (fragmentShader->mUsesPointCoord && sm3)
1581 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001582 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1583 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001584 }
1585
1586 if (fragmentShader->mUsesFrontFacing)
1587 {
1588 pixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1589 }
1590
1591 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1592 {
1593 if (varying->reg >= 0)
1594 {
1595 for (int i = 0; i < varying->size; i++)
1596 {
1597 int rows = VariableRowCount(varying->type);
1598 for (int j = 0; j < rows; j++)
1599 {
1600 std::string n = str(varying->reg + i * rows + j);
1601 pixelHLSL += " " + varying->name;
1602
1603 if (varying->array)
1604 {
1605 pixelHLSL += "[" + str(i) + "]";
1606 }
1607
1608 if (rows > 1)
1609 {
1610 pixelHLSL += "[" + str(j) + "]";
1611 }
1612
1613 pixelHLSL += " = input.v" + n + ";\n";
1614 }
1615 }
1616 }
1617 else UNREACHABLE();
1618 }
1619
1620 pixelHLSL += "\n"
1621 " gl_main();\n"
1622 "\n"
1623 " PS_OUTPUT output;\n"
1624 " output.gl_Color[0] = gl_Color[0];\n"
1625 "\n"
1626 " return output;\n"
1627 "}\n";
1628
1629 return true;
1630}
1631
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001632bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1633{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001634 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001635
1636 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001637 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001638 if (format != GL_PROGRAM_BINARY_ANGLE)
1639 {
1640 infoLog.append("Invalid program binary format.");
1641 return false;
1642 }
1643
1644 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001645 stream.read(&version);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001646 if (version != BUILD_REVISION)
1647 {
1648 infoLog.append("Invalid program binary version.");
1649 return false;
1650 }
1651
1652 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1653 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001654 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001655 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001656 stream.read(&name);
1657 mLinkedAttribute[i].name = name;
1658 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001659 }
1660
1661 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1662 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001663 stream.read(&mSamplersPS[i].active);
1664 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001665
1666 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001667 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001668 mSamplersPS[i].textureType = (TextureType) textureType;
1669 }
1670
1671 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1672 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001673 stream.read(&mSamplersVS[i].active);
1674 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001675
1676 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001677 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001678 mSamplersVS[i].textureType = (TextureType) textureType;
1679 }
1680
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001681 stream.read(&mUsedVertexSamplerRange);
1682 stream.read(&mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001683
1684 unsigned int size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001685 stream.read(&size);
1686 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001687 {
1688 infoLog.append("Invalid program binary.");
1689 return false;
1690 }
1691
1692 mUniforms.resize(size);
1693 for (unsigned int i = 0; i < size; ++i)
1694 {
1695 GLenum type;
1696 std::string _name;
1697 unsigned int arraySize;
1698
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001699 stream.read(&type);
1700 stream.read(&_name);
1701 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001702
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001703 mUniforms[i] = new Uniform(type, _name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001704
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001705 stream.read(&mUniforms[i]->ps.float4Index);
1706 stream.read(&mUniforms[i]->ps.samplerIndex);
1707 stream.read(&mUniforms[i]->ps.boolIndex);
1708 stream.read(&mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001709
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001710 stream.read(&mUniforms[i]->vs.float4Index);
1711 stream.read(&mUniforms[i]->vs.samplerIndex);
1712 stream.read(&mUniforms[i]->vs.boolIndex);
1713 stream.read(&mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001714 }
1715
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001716 stream.read(&size);
1717 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001718 {
1719 infoLog.append("Invalid program binary.");
1720 return false;
1721 }
1722
1723 mUniformIndex.resize(size);
1724 for (unsigned int i = 0; i < size; ++i)
1725 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001726 stream.read(&mUniformIndex[i].name);
1727 stream.read(&mUniformIndex[i].element);
1728 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001729 }
1730
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001731 stream.read(&mDxDepthRangeLocation);
1732 stream.read(&mDxDepthLocation);
1733 stream.read(&mDxCoordLocation);
1734 stream.read(&mDxHalfPixelSizeLocation);
1735 stream.read(&mDxFrontCCWLocation);
1736 stream.read(&mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001737
1738 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001739 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001740
1741 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001742 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001743
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001744 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001745
1746 const D3DCAPS9 *binaryIdentifier = (const D3DCAPS9*) ptr;
1747 ptr += sizeof(GUID);
1748
daniel@transgaming.com621ce052012-10-31 17:52:29 +00001749 // D3D9_REPLACE
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001750 D3DADAPTER_IDENTIFIER9 *currentIdentifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001751 if (memcmp(&currentIdentifier->DeviceIdentifier, binaryIdentifier, sizeof(GUID)) != 0)
1752 {
1753 infoLog.append("Invalid program binary.");
1754 return false;
1755 }
1756
1757 const char *pixelShaderFunction = ptr;
1758 ptr += pixelShaderSize;
1759
1760 const char *vertexShaderFunction = ptr;
1761 ptr += vertexShaderSize;
1762
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001763 mPixelExecutable = mRenderer->createPixelShader(reinterpret_cast<const DWORD*>(pixelShaderFunction), pixelShaderSize);
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001764 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001765 {
1766 infoLog.append("Could not create pixel shader.");
1767 return false;
1768 }
1769
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001770 mVertexExecutable = mRenderer->createVertexShader(reinterpret_cast<const DWORD*>(vertexShaderFunction), vertexShaderSize);
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001771 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001772 {
1773 infoLog.append("Could not create vertex shader.");
1774 mPixelExecutable->Release();
1775 mPixelExecutable = NULL;
1776 return false;
1777 }
1778
1779 return true;
1780}
1781
1782bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1783{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001784 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001785
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001786 stream.write(GL_PROGRAM_BINARY_ANGLE);
1787 stream.write(BUILD_REVISION);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001788
1789 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1790 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001791 stream.write(mLinkedAttribute[i].type);
1792 stream.write(mLinkedAttribute[i].name);
1793 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001794 }
1795
1796 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1797 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001798 stream.write(mSamplersPS[i].active);
1799 stream.write(mSamplersPS[i].logicalTextureUnit);
1800 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001801 }
1802
1803 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1804 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001805 stream.write(mSamplersVS[i].active);
1806 stream.write(mSamplersVS[i].logicalTextureUnit);
1807 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001808 }
1809
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001810 stream.write(mUsedVertexSamplerRange);
1811 stream.write(mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001812
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001813 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001814 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1815 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001816 stream.write(mUniforms[i]->type);
1817 stream.write(mUniforms[i]->_name);
1818 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001819
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001820 stream.write(mUniforms[i]->ps.float4Index);
1821 stream.write(mUniforms[i]->ps.samplerIndex);
1822 stream.write(mUniforms[i]->ps.boolIndex);
1823 stream.write(mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001824
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001825 stream.write(mUniforms[i]->vs.float4Index);
1826 stream.write(mUniforms[i]->vs.samplerIndex);
1827 stream.write(mUniforms[i]->vs.boolIndex);
1828 stream.write(mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001829 }
1830
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001831 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001832 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1833 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001834 stream.write(mUniformIndex[i].name);
1835 stream.write(mUniformIndex[i].element);
1836 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001837 }
1838
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001839 stream.write(mDxDepthRangeLocation);
1840 stream.write(mDxDepthLocation);
1841 stream.write(mDxCoordLocation);
1842 stream.write(mDxHalfPixelSizeLocation);
1843 stream.write(mDxFrontCCWLocation);
1844 stream.write(mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001845
1846 UINT pixelShaderSize;
1847 HRESULT result = mPixelExecutable->GetFunction(NULL, &pixelShaderSize);
1848 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001849 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001850
1851 UINT vertexShaderSize;
1852 result = mVertexExecutable->GetFunction(NULL, &vertexShaderSize);
1853 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001854 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001855
daniel@transgaming.com621ce052012-10-31 17:52:29 +00001856 // D3D9_REPLACE
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001857 D3DADAPTER_IDENTIFIER9 *identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001858
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001859 GLsizei streamLength = stream.length();
1860 const void *streamData = stream.data();
1861
1862 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001863 if (totalLength > bufSize)
1864 {
1865 if (length)
1866 {
1867 *length = 0;
1868 }
1869
1870 return false;
1871 }
1872
1873 if (binary)
1874 {
1875 char *ptr = (char*) binary;
1876
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001877 memcpy(ptr, streamData, streamLength);
1878 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001879
1880 memcpy(ptr, &identifier->DeviceIdentifier, sizeof(GUID));
1881 ptr += sizeof(GUID);
1882
1883 result = mPixelExecutable->GetFunction(ptr, &pixelShaderSize);
1884 ASSERT(SUCCEEDED(result));
1885 ptr += pixelShaderSize;
1886
1887 result = mVertexExecutable->GetFunction(ptr, &vertexShaderSize);
1888 ASSERT(SUCCEEDED(result));
1889 ptr += vertexShaderSize;
1890
1891 ASSERT(ptr - totalLength == binary);
1892 }
1893
1894 if (length)
1895 {
1896 *length = totalLength;
1897 }
1898
1899 return true;
1900}
1901
1902GLint ProgramBinary::getLength()
1903{
1904 GLint length;
1905 if (save(NULL, INT_MAX, &length))
1906 {
1907 return length;
1908 }
1909 else
1910 {
1911 return 0;
1912 }
1913}
1914
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001915bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001916{
1917 if (!fragmentShader || !fragmentShader->isCompiled())
1918 {
1919 return false;
1920 }
1921
1922 if (!vertexShader || !vertexShader->isCompiled())
1923 {
1924 return false;
1925 }
1926
1927 std::string pixelHLSL = fragmentShader->getHLSL();
1928 std::string vertexHLSL = vertexShader->getHLSL();
1929
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001930 if (!linkVaryings(infoLog, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001931 {
1932 return false;
1933 }
1934
1935 Context *context = getContext();
1936 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1937 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1938
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001939 ID3D10Blob *vertexBinary = compileToBinary(infoLog, vertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1940 ID3D10Blob *pixelBinary = compileToBinary(infoLog, pixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001941
1942 if (vertexBinary && pixelBinary)
1943 {
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001944 mVertexExecutable = mRenderer->createVertexShader((DWORD*)vertexBinary->GetBufferPointer(), vertexBinary->GetBufferSize());
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001945 if (!mVertexExecutable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001946 {
1947 return error(GL_OUT_OF_MEMORY, false);
1948 }
1949
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001950 mPixelExecutable = mRenderer->createPixelShader((DWORD*)pixelBinary->GetBufferPointer(), pixelBinary->GetBufferSize());
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001951 if (!mPixelExecutable)
1952 {
1953 mVertexExecutable->Release();
1954 mVertexExecutable = NULL;
1955 return error(GL_OUT_OF_MEMORY, false);
1956 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001957
1958 vertexBinary->Release();
1959 pixelBinary->Release();
1960 vertexBinary = NULL;
1961 pixelBinary = NULL;
1962
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001963 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001964 {
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001965 return false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001966 }
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001967
1968 if (!linkUniforms(infoLog, GL_FRAGMENT_SHADER, mConstantTablePS))
1969 {
1970 return false;
1971 }
1972
1973 if (!linkUniforms(infoLog, GL_VERTEX_SHADER, mConstantTableVS))
1974 {
1975 return false;
1976 }
1977
1978 // these uniforms are searched as already-decorated because gl_ and dx_
1979 // are reserved prefixes, and do not receive additional decoration
1980 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
1981 mDxDepthLocation = getUniformLocation("dx_Depth");
1982 mDxCoordLocation = getUniformLocation("dx_Coord");
1983 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
1984 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
1985 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
1986
1987 context->markDxUniformsDirty();
1988
1989 return true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001990 }
1991
1992 return false;
1993}
1994
1995// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001996bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001997{
1998 unsigned int usedLocations = 0;
1999
2000 // Link attributes that have a binding location
2001 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2002 {
2003 int location = attributeBindings.getAttributeBinding(attribute->name);
2004
2005 if (location != -1) // Set by glBindAttribLocation
2006 {
2007 if (!mLinkedAttribute[location].name.empty())
2008 {
2009 // Multiple active attributes bound to the same location; not an error
2010 }
2011
2012 mLinkedAttribute[location] = *attribute;
2013
2014 int rows = VariableRowCount(attribute->type);
2015
2016 if (rows + location > MAX_VERTEX_ATTRIBS)
2017 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002018 infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002019
2020 return false;
2021 }
2022
2023 for (int i = 0; i < rows; i++)
2024 {
2025 usedLocations |= 1 << (location + i);
2026 }
2027 }
2028 }
2029
2030 // Link attributes that don't have a binding location
2031 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2032 {
2033 int location = attributeBindings.getAttributeBinding(attribute->name);
2034
2035 if (location == -1) // Not set by glBindAttribLocation
2036 {
2037 int rows = VariableRowCount(attribute->type);
2038 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2039
2040 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2041 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002042 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002043
2044 return false; // Fail to link
2045 }
2046
2047 mLinkedAttribute[availableIndex] = *attribute;
2048 }
2049 }
2050
2051 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2052 {
2053 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
2054 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
2055
2056 for (int r = 0; r < rows; r++)
2057 {
2058 mSemanticIndex[attributeIndex++] = index++;
2059 }
2060 }
2061
2062 return true;
2063}
2064
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002065bool ProgramBinary::linkUniforms(InfoLog &infoLog, GLenum shader, D3DConstantTable *constantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002066{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002067 for (unsigned int constantIndex = 0; constantIndex < constantTable->constants(); constantIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002068 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002069 const D3DConstant *constant = constantTable->getConstant(constantIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002070
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002071 if (!defineUniform(infoLog, shader, constant))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002072 {
2073 return false;
2074 }
2075 }
2076
2077 return true;
2078}
2079
2080// Adds the description of a constant found in the binary shader to the list of uniforms
2081// Returns true if succesful (uniform not already defined)
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002082bool ProgramBinary::defineUniform(InfoLog &infoLog, GLenum shader, const D3DConstant *constant, std::string name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002083{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002084 if (constant->registerSet == D3DConstant::RS_SAMPLER)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002085 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002086 for (unsigned int i = 0; i < constant->registerCount; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002087 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002088 const D3DConstant *psConstant = mConstantTablePS->getConstantByName(constant->name.c_str());
2089 const D3DConstant *vsConstant = mConstantTableVS->getConstantByName(constant->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002090
2091 if (psConstant)
2092 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002093 unsigned int samplerIndex = psConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002094
2095 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2096 {
2097 mSamplersPS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002098 mSamplersPS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002099 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2100 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2101 }
2102 else
2103 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002104 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002105 return false;
2106 }
2107 }
2108
2109 if (vsConstant)
2110 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002111 unsigned int samplerIndex = vsConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002112
2113 if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
2114 {
2115 mSamplersVS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002116 mSamplersVS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002117 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2118 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2119 }
2120 else
2121 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002122 infoLog.append("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002123 return false;
2124 }
2125 }
2126 }
2127 }
2128
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002129 switch(constant->typeClass)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002130 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002131 case D3DConstant::CLASS_STRUCT:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002132 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002133 for (unsigned int arrayIndex = 0; arrayIndex < constant->elements; arrayIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002134 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002135 for (unsigned int field = 0; field < constant->structMembers[arrayIndex].size(); field++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002136 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002137 const D3DConstant *fieldConstant = constant->structMembers[arrayIndex][field];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002138
apatrick@chromium.org85fee292012-09-06 00:43:06 +00002139 std::string structIndex = (constant->elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002140
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002141 if (!defineUniform(infoLog, shader, fieldConstant, name + constant->name + structIndex + "."))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002142 {
2143 return false;
2144 }
2145 }
2146 }
2147
2148 return true;
2149 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002150 case D3DConstant::CLASS_SCALAR:
2151 case D3DConstant::CLASS_VECTOR:
2152 case D3DConstant::CLASS_MATRIX_COLUMNS:
2153 case D3DConstant::CLASS_OBJECT:
2154 return defineUniform(shader, constant, name + constant->name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002155 default:
2156 UNREACHABLE();
2157 return false;
2158 }
2159}
2160
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002161bool ProgramBinary::defineUniform(GLenum shader, const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002162{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002163 Uniform *uniform = createUniform(constant, _name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002164
2165 if(!uniform)
2166 {
2167 return false;
2168 }
2169
2170 // Check if already defined
2171 GLint location = getUniformLocation(uniform->name);
2172 GLenum type = uniform->type;
2173
2174 if (location >= 0)
2175 {
2176 delete uniform;
2177 uniform = mUniforms[mUniformIndex[location].index];
2178 }
2179
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002180 if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constant);
2181 if (shader == GL_VERTEX_SHADER) uniform->vs.set(constant);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002182
2183 if (location >= 0)
2184 {
2185 return uniform->type == type;
2186 }
2187
2188 mUniforms.push_back(uniform);
2189 unsigned int uniformIndex = mUniforms.size() - 1;
2190
2191 for (unsigned int i = 0; i < uniform->arraySize; ++i)
2192 {
2193 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
2194 }
2195
2196 return true;
2197}
2198
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002199Uniform *ProgramBinary::createUniform(const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002200{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002201 if (constant->rows == 1) // Vectors and scalars
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002202 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002203 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002204 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002205 case D3DConstant::PT_SAMPLER2D:
2206 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002207 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002208 case 1: return new Uniform(GL_SAMPLER_2D, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002209 default: UNREACHABLE();
2210 }
2211 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002212 case D3DConstant::PT_SAMPLERCUBE:
2213 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002214 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002215 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002216 default: UNREACHABLE();
2217 }
2218 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002219 case D3DConstant::PT_BOOL:
2220 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002221 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002222 case 1: return new Uniform(GL_BOOL, _name, constant->elements);
2223 case 2: return new Uniform(GL_BOOL_VEC2, _name, constant->elements);
2224 case 3: return new Uniform(GL_BOOL_VEC3, _name, constant->elements);
2225 case 4: return new Uniform(GL_BOOL_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002226 default: UNREACHABLE();
2227 }
2228 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002229 case D3DConstant::PT_INT:
2230 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002231 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002232 case 1: return new Uniform(GL_INT, _name, constant->elements);
2233 case 2: return new Uniform(GL_INT_VEC2, _name, constant->elements);
2234 case 3: return new Uniform(GL_INT_VEC3, _name, constant->elements);
2235 case 4: return new Uniform(GL_INT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002236 default: UNREACHABLE();
2237 }
2238 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002239 case D3DConstant::PT_FLOAT:
2240 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002241 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002242 case 1: return new Uniform(GL_FLOAT, _name, constant->elements);
2243 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constant->elements);
2244 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constant->elements);
2245 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002246 default: UNREACHABLE();
2247 }
2248 break;
2249 default:
2250 UNREACHABLE();
2251 }
2252 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002253 else if (constant->rows == constant->columns) // Square matrices
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002254 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002255 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002256 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002257 case D3DConstant::PT_FLOAT:
2258 switch (constant->rows)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002259 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002260 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constant->elements);
2261 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constant->elements);
2262 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002263 default: UNREACHABLE();
2264 }
2265 break;
2266 default: UNREACHABLE();
2267 }
2268 }
2269 else UNREACHABLE();
2270
2271 return 0;
2272}
2273
2274// This method needs to match OutputHLSL::decorate
2275std::string ProgramBinary::decorateAttribute(const std::string &name)
2276{
2277 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2278 {
2279 return "_" + name;
2280 }
2281
2282 return name;
2283}
2284
2285std::string ProgramBinary::undecorateUniform(const std::string &_name)
2286{
2287 std::string name = _name;
2288
2289 // Remove any structure field decoration
2290 size_t pos = 0;
2291 while ((pos = name.find("._", pos)) != std::string::npos)
2292 {
2293 name.replace(pos, 2, ".");
2294 }
2295
2296 // Remove the leading decoration
2297 if (name[0] == '_')
2298 {
2299 return name.substr(1);
2300 }
2301 else if (name.compare(0, 3, "ar_") == 0)
2302 {
2303 return name.substr(3);
2304 }
2305
2306 return name;
2307}
2308
2309void ProgramBinary::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
2310{
2311 float vector[D3D9_MAX_FLOAT_CONSTANTS * 4];
2312 BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS];
2313
2314 if (targetUniform->ps.float4Index >= 0 || targetUniform->vs.float4Index >= 0)
2315 {
2316 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2317 for (int i = 0; i < count; i++)
2318 {
2319 for (int j = 0; j < 4; j++)
2320 {
2321 if (j < width)
2322 {
2323 vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f;
2324 }
2325 else
2326 {
2327 vector[i * 4 + j] = 0.0f;
2328 }
2329 }
2330 }
2331 }
2332
2333 if (targetUniform->ps.boolIndex >= 0 || targetUniform->vs.boolIndex >= 0)
2334 {
2335 int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0;
2336 int vsCount = targetUniform->vs.boolIndex >= 0 ? targetUniform->vs.registerCount : 0;
2337 int copyCount = std::min(count * width, std::max(psCount, vsCount));
2338 ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS);
2339 for (int i = 0; i < copyCount; i++)
2340 {
2341 boolVector[i] = v[i] != GL_FALSE;
2342 }
2343 }
2344
2345 if (targetUniform->ps.float4Index >= 0)
2346 {
2347 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount);
2348 }
2349
2350 if (targetUniform->ps.boolIndex >= 0)
2351 {
2352 mDevice->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount);
2353 }
2354
2355 if (targetUniform->vs.float4Index >= 0)
2356 {
2357 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount);
2358 }
2359
2360 if (targetUniform->vs.boolIndex >= 0)
2361 {
2362 mDevice->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount);
2363 }
2364}
2365
2366bool ProgramBinary::applyUniformnfv(Uniform *targetUniform, const GLfloat *v)
2367{
2368 if (targetUniform->ps.registerCount)
2369 {
2370 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount);
2371 }
2372
2373 if (targetUniform->vs.registerCount)
2374 {
2375 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount);
2376 }
2377
2378 return true;
2379}
2380
2381bool ProgramBinary::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2382{
2383 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002384 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002385
2386 for (int i = 0; i < count; i++)
2387 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002388 vector[i] = Vector4((float)v[i], 0, 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002389 }
2390
2391 if (targetUniform->ps.registerCount)
2392 {
2393 if (targetUniform->ps.samplerIndex >= 0)
2394 {
2395 unsigned int firstIndex = targetUniform->ps.samplerIndex;
2396
2397 for (int i = 0; i < count; i++)
2398 {
2399 unsigned int samplerIndex = firstIndex + i;
2400
2401 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2402 {
2403 ASSERT(mSamplersPS[samplerIndex].active);
2404 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
2405 }
2406 }
2407 }
2408 else
2409 {
2410 ASSERT(targetUniform->ps.float4Index >= 0);
2411 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount);
2412 }
2413 }
2414
2415 if (targetUniform->vs.registerCount)
2416 {
2417 if (targetUniform->vs.samplerIndex >= 0)
2418 {
2419 unsigned int firstIndex = targetUniform->vs.samplerIndex;
2420
2421 for (int i = 0; i < count; i++)
2422 {
2423 unsigned int samplerIndex = firstIndex + i;
2424
2425 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2426 {
2427 ASSERT(mSamplersVS[samplerIndex].active);
2428 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2429 }
2430 }
2431 }
2432 else
2433 {
2434 ASSERT(targetUniform->vs.float4Index >= 0);
2435 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2436 }
2437 }
2438
2439 return true;
2440}
2441
2442bool ProgramBinary::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2443{
2444 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002445 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002446
2447 for (int i = 0; i < count; i++)
2448 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002449 vector[i] = Vector4((float)v[0], (float)v[1], 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002450
2451 v += 2;
2452 }
2453
2454 applyUniformniv(targetUniform, count, vector);
2455
2456 return true;
2457}
2458
2459bool ProgramBinary::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2460{
2461 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002462 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002463
2464 for (int i = 0; i < count; i++)
2465 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002466 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002467
2468 v += 3;
2469 }
2470
2471 applyUniformniv(targetUniform, count, vector);
2472
2473 return true;
2474}
2475
2476bool ProgramBinary::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2477{
2478 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002479 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002480
2481 for (int i = 0; i < count; i++)
2482 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002483 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002484
2485 v += 4;
2486 }
2487
2488 applyUniformniv(targetUniform, count, vector);
2489
2490 return true;
2491}
2492
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002493void ProgramBinary::applyUniformniv(Uniform *targetUniform, GLsizei count, const Vector4 *vector)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002494{
2495 if (targetUniform->ps.registerCount)
2496 {
2497 ASSERT(targetUniform->ps.float4Index >= 0);
2498 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount);
2499 }
2500
2501 if (targetUniform->vs.registerCount)
2502 {
2503 ASSERT(targetUniform->vs.float4Index >= 0);
2504 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2505 }
2506}
2507
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002508bool ProgramBinary::isValidated() const
2509{
2510 return mValidated;
2511}
2512
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002513void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2514{
2515 // Skip over inactive attributes
2516 unsigned int activeAttribute = 0;
2517 unsigned int attribute;
2518 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2519 {
2520 if (mLinkedAttribute[attribute].name.empty())
2521 {
2522 continue;
2523 }
2524
2525 if (activeAttribute == index)
2526 {
2527 break;
2528 }
2529
2530 activeAttribute++;
2531 }
2532
2533 if (bufsize > 0)
2534 {
2535 const char *string = mLinkedAttribute[attribute].name.c_str();
2536
2537 strncpy(name, string, bufsize);
2538 name[bufsize - 1] = '\0';
2539
2540 if (length)
2541 {
2542 *length = strlen(name);
2543 }
2544 }
2545
2546 *size = 1; // Always a single 'type' instance
2547
2548 *type = mLinkedAttribute[attribute].type;
2549}
2550
2551GLint ProgramBinary::getActiveAttributeCount()
2552{
2553 int count = 0;
2554
2555 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2556 {
2557 if (!mLinkedAttribute[attributeIndex].name.empty())
2558 {
2559 count++;
2560 }
2561 }
2562
2563 return count;
2564}
2565
2566GLint ProgramBinary::getActiveAttributeMaxLength()
2567{
2568 int maxLength = 0;
2569
2570 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2571 {
2572 if (!mLinkedAttribute[attributeIndex].name.empty())
2573 {
2574 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2575 }
2576 }
2577
2578 return maxLength;
2579}
2580
2581void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2582{
2583 // Skip over internal uniforms
2584 unsigned int activeUniform = 0;
2585 unsigned int uniform;
2586 for (uniform = 0; uniform < mUniforms.size(); uniform++)
2587 {
2588 if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0)
2589 {
2590 continue;
2591 }
2592
2593 if (activeUniform == index)
2594 {
2595 break;
2596 }
2597
2598 activeUniform++;
2599 }
2600
2601 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2602
2603 if (bufsize > 0)
2604 {
2605 std::string string = mUniforms[uniform]->name;
2606
2607 if (mUniforms[uniform]->isArray())
2608 {
2609 string += "[0]";
2610 }
2611
2612 strncpy(name, string.c_str(), bufsize);
2613 name[bufsize - 1] = '\0';
2614
2615 if (length)
2616 {
2617 *length = strlen(name);
2618 }
2619 }
2620
2621 *size = mUniforms[uniform]->arraySize;
2622
2623 *type = mUniforms[uniform]->type;
2624}
2625
2626GLint ProgramBinary::getActiveUniformCount()
2627{
2628 int count = 0;
2629
2630 unsigned int numUniforms = mUniforms.size();
2631 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2632 {
2633 if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2634 {
2635 count++;
2636 }
2637 }
2638
2639 return count;
2640}
2641
2642GLint ProgramBinary::getActiveUniformMaxLength()
2643{
2644 int maxLength = 0;
2645
2646 unsigned int numUniforms = mUniforms.size();
2647 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2648 {
2649 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2650 {
2651 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2652 if (mUniforms[uniformIndex]->isArray())
2653 {
2654 length += 3; // Counting in "[0]".
2655 }
2656 maxLength = std::max(length, maxLength);
2657 }
2658 }
2659
2660 return maxLength;
2661}
2662
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002663void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002664{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002665 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002666 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002667 {
2668 mValidated = false;
2669 }
2670 else
2671 {
2672 mValidated = true;
2673 }
2674}
2675
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002676bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002677{
2678 // if any two active samplers in a program are of different types, but refer to the same
2679 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2680 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2681
2682 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
2683 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2684
2685 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2686 {
2687 textureUnitType[i] = TEXTURE_UNKNOWN;
2688 }
2689
2690 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2691 {
2692 if (mSamplersPS[i].active)
2693 {
2694 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2695
2696 if (unit >= maxCombinedTextureImageUnits)
2697 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002698 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002699 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002700 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002701 }
2702
2703 return false;
2704 }
2705
2706 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2707 {
2708 if (mSamplersPS[i].textureType != textureUnitType[unit])
2709 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002710 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002711 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002712 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002713 }
2714
2715 return false;
2716 }
2717 }
2718 else
2719 {
2720 textureUnitType[unit] = mSamplersPS[i].textureType;
2721 }
2722 }
2723 }
2724
2725 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2726 {
2727 if (mSamplersVS[i].active)
2728 {
2729 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2730
2731 if (unit >= maxCombinedTextureImageUnits)
2732 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002733 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002734 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002735 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002736 }
2737
2738 return false;
2739 }
2740
2741 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2742 {
2743 if (mSamplersVS[i].textureType != textureUnitType[unit])
2744 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002745 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002746 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002747 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002748 }
2749
2750 return false;
2751 }
2752 }
2753 else
2754 {
2755 textureUnitType[unit] = mSamplersVS[i].textureType;
2756 }
2757 }
2758 }
2759
2760 return true;
2761}
2762
2763GLint ProgramBinary::getDxDepthRangeLocation() const
2764{
2765 return mDxDepthRangeLocation;
2766}
2767
2768GLint ProgramBinary::getDxDepthLocation() const
2769{
2770 return mDxDepthLocation;
2771}
2772
2773GLint ProgramBinary::getDxCoordLocation() const
2774{
2775 return mDxCoordLocation;
2776}
2777
2778GLint ProgramBinary::getDxHalfPixelSizeLocation() const
2779{
2780 return mDxHalfPixelSizeLocation;
2781}
2782
2783GLint ProgramBinary::getDxFrontCCWLocation() const
2784{
2785 return mDxFrontCCWLocation;
2786}
2787
2788GLint ProgramBinary::getDxPointsOrLinesLocation() const
2789{
2790 return mDxPointsOrLinesLocation;
2791}
2792
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002793ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2794{
2795}
2796
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002797}