blob: e3ca5702fa31dab2a8b00c5abf71b4a0f3b491cb [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/ProgramBinary.h"
12
13#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000014#include "common/version.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000015
16#include "libGLESv2/main.h"
17#include "libGLESv2/Shader.h"
18#include "libGLESv2/utilities.h"
19
20#include <string>
21
22#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
23#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3
24#endif
25
26namespace gl
27{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000028std::string str(int i)
29{
30 char buffer[20];
31 snprintf(buffer, sizeof(buffer), "%d", i);
32 return buffer;
33}
34
35Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize)
36 : type(type), _name(_name), name(ProgramBinary::undecorateUniform(_name)), arraySize(arraySize)
37{
38 int bytes = UniformInternalSize(type) * arraySize;
39 data = new unsigned char[bytes];
40 memset(data, 0, bytes);
41 dirty = true;
42}
43
44Uniform::~Uniform()
45{
46 delete[] data;
47}
48
49bool Uniform::isArray()
50{
daniel@transgaming.com22ba0f72012-09-27 17:46:04 +000051 size_t dot = _name.find_last_of('.');
52 if (dot == std::string::npos) dot = -1;
53
54 return _name.compare(dot + 1, dot + 4, "ar_") == 0;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000055}
56
57UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index)
58 : name(ProgramBinary::undecorateUniform(_name)), element(element), index(index)
59{
60}
61
daniel@transgaming.come87ca002012-07-24 18:30:43 +000062unsigned int ProgramBinary::mCurrentSerial = 1;
63
daniel@transgaming.com70062c92012-11-28 19:32:30 +000064ProgramBinary::ProgramBinary(rx::Renderer *renderer) : RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000065{
daniel@transgaming.com70062c92012-11-28 19:32:30 +000066 ASSERT(dynamic_cast<rx::Renderer9*>(renderer) != NULL); // D3D9_REPLACE
67 mRenderer = static_cast<rx::Renderer9*>(renderer);
daniel@transgaming.come4733d72012-10-31 18:07:01 +000068 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
daniel@transgaming.come3e826d2012-11-28 19:42:35 +00001048 HRESULT result = S_OK;
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;
daniel@transgaming.com7d738a22012-11-28 19:43:08 +00001090 result = mRenderer->compileShaderSource(hlsl, g_fakepath, profile, flags | extraFlags[i], &binary, &errorMessage);
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001091
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
daniel@transgaming.com9549bea2012-11-28 20:57:23 +00001320 const bool sm3 = mRenderer->getMajorShaderModel() >= 3;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001321 Context *context = getContext();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001322 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.com4ca789e2012-10-31 18:46:40 +00001749 GUID identifier = mRenderer->getAdapterIdentifier();
1750 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001751 {
1752 infoLog.append("Invalid program binary.");
1753 return false;
1754 }
1755
1756 const char *pixelShaderFunction = ptr;
1757 ptr += pixelShaderSize;
1758
1759 const char *vertexShaderFunction = ptr;
1760 ptr += vertexShaderSize;
1761
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001762 mPixelExecutable = mRenderer->createPixelShader(reinterpret_cast<const DWORD*>(pixelShaderFunction), pixelShaderSize);
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001763 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001764 {
1765 infoLog.append("Could not create pixel shader.");
1766 return false;
1767 }
1768
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001769 mVertexExecutable = mRenderer->createVertexShader(reinterpret_cast<const DWORD*>(vertexShaderFunction), vertexShaderSize);
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001770 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001771 {
1772 infoLog.append("Could not create vertex shader.");
1773 mPixelExecutable->Release();
1774 mPixelExecutable = NULL;
1775 return false;
1776 }
1777
1778 return true;
1779}
1780
1781bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1782{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001783 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001784
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001785 stream.write(GL_PROGRAM_BINARY_ANGLE);
1786 stream.write(BUILD_REVISION);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001787
1788 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1789 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001790 stream.write(mLinkedAttribute[i].type);
1791 stream.write(mLinkedAttribute[i].name);
1792 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001793 }
1794
1795 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1796 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001797 stream.write(mSamplersPS[i].active);
1798 stream.write(mSamplersPS[i].logicalTextureUnit);
1799 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001800 }
1801
1802 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1803 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001804 stream.write(mSamplersVS[i].active);
1805 stream.write(mSamplersVS[i].logicalTextureUnit);
1806 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001807 }
1808
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001809 stream.write(mUsedVertexSamplerRange);
1810 stream.write(mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001811
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001812 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001813 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1814 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001815 stream.write(mUniforms[i]->type);
1816 stream.write(mUniforms[i]->_name);
1817 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001818
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001819 stream.write(mUniforms[i]->ps.float4Index);
1820 stream.write(mUniforms[i]->ps.samplerIndex);
1821 stream.write(mUniforms[i]->ps.boolIndex);
1822 stream.write(mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001823
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001824 stream.write(mUniforms[i]->vs.float4Index);
1825 stream.write(mUniforms[i]->vs.samplerIndex);
1826 stream.write(mUniforms[i]->vs.boolIndex);
1827 stream.write(mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001828 }
1829
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001830 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001831 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1832 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001833 stream.write(mUniformIndex[i].name);
1834 stream.write(mUniformIndex[i].element);
1835 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001836 }
1837
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001838 stream.write(mDxDepthRangeLocation);
1839 stream.write(mDxDepthLocation);
1840 stream.write(mDxCoordLocation);
1841 stream.write(mDxHalfPixelSizeLocation);
1842 stream.write(mDxFrontCCWLocation);
1843 stream.write(mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001844
1845 UINT pixelShaderSize;
1846 HRESULT result = mPixelExecutable->GetFunction(NULL, &pixelShaderSize);
1847 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001848 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001849
1850 UINT vertexShaderSize;
1851 result = mVertexExecutable->GetFunction(NULL, &vertexShaderSize);
1852 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001853 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001854
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001855 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001856
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001857 GLsizei streamLength = stream.length();
1858 const void *streamData = stream.data();
1859
1860 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001861 if (totalLength > bufSize)
1862 {
1863 if (length)
1864 {
1865 *length = 0;
1866 }
1867
1868 return false;
1869 }
1870
1871 if (binary)
1872 {
1873 char *ptr = (char*) binary;
1874
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001875 memcpy(ptr, streamData, streamLength);
1876 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001877
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001878 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001879 ptr += sizeof(GUID);
1880
1881 result = mPixelExecutable->GetFunction(ptr, &pixelShaderSize);
1882 ASSERT(SUCCEEDED(result));
1883 ptr += pixelShaderSize;
1884
1885 result = mVertexExecutable->GetFunction(ptr, &vertexShaderSize);
1886 ASSERT(SUCCEEDED(result));
1887 ptr += vertexShaderSize;
1888
1889 ASSERT(ptr - totalLength == binary);
1890 }
1891
1892 if (length)
1893 {
1894 *length = totalLength;
1895 }
1896
1897 return true;
1898}
1899
1900GLint ProgramBinary::getLength()
1901{
1902 GLint length;
1903 if (save(NULL, INT_MAX, &length))
1904 {
1905 return length;
1906 }
1907 else
1908 {
1909 return 0;
1910 }
1911}
1912
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001913bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001914{
1915 if (!fragmentShader || !fragmentShader->isCompiled())
1916 {
1917 return false;
1918 }
1919
1920 if (!vertexShader || !vertexShader->isCompiled())
1921 {
1922 return false;
1923 }
1924
1925 std::string pixelHLSL = fragmentShader->getHLSL();
1926 std::string vertexHLSL = vertexShader->getHLSL();
1927
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001928 if (!linkVaryings(infoLog, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001929 {
1930 return false;
1931 }
1932
daniel@transgaming.com9549bea2012-11-28 20:57:23 +00001933 const char *vertexProfile = mRenderer->getMajorShaderModel() >= 3 ? "vs_3_0" : "vs_2_0";
1934 const char *pixelProfile = mRenderer->getMajorShaderModel() >= 3 ? "ps_3_0" : "ps_2_0";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001935
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001936 ID3D10Blob *vertexBinary = compileToBinary(infoLog, vertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1937 ID3D10Blob *pixelBinary = compileToBinary(infoLog, pixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001938
1939 if (vertexBinary && pixelBinary)
1940 {
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001941 mVertexExecutable = mRenderer->createVertexShader((DWORD*)vertexBinary->GetBufferPointer(), vertexBinary->GetBufferSize());
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001942 if (!mVertexExecutable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001943 {
1944 return error(GL_OUT_OF_MEMORY, false);
1945 }
1946
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001947 mPixelExecutable = mRenderer->createPixelShader((DWORD*)pixelBinary->GetBufferPointer(), pixelBinary->GetBufferSize());
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001948 if (!mPixelExecutable)
1949 {
1950 mVertexExecutable->Release();
1951 mVertexExecutable = NULL;
1952 return error(GL_OUT_OF_MEMORY, false);
1953 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001954
1955 vertexBinary->Release();
1956 pixelBinary->Release();
1957 vertexBinary = NULL;
1958 pixelBinary = NULL;
1959
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001960 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001961 {
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001962 return false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001963 }
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001964
1965 if (!linkUniforms(infoLog, GL_FRAGMENT_SHADER, mConstantTablePS))
1966 {
1967 return false;
1968 }
1969
1970 if (!linkUniforms(infoLog, GL_VERTEX_SHADER, mConstantTableVS))
1971 {
1972 return false;
1973 }
1974
1975 // these uniforms are searched as already-decorated because gl_ and dx_
1976 // are reserved prefixes, and do not receive additional decoration
1977 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
1978 mDxDepthLocation = getUniformLocation("dx_Depth");
1979 mDxCoordLocation = getUniformLocation("dx_Coord");
1980 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
1981 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
1982 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
1983
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001984 Context *context = getContext();
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001985 context->markDxUniformsDirty();
1986
1987 return true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001988 }
1989
1990 return false;
1991}
1992
1993// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001994bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001995{
1996 unsigned int usedLocations = 0;
1997
1998 // Link attributes that have a binding location
1999 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2000 {
2001 int location = attributeBindings.getAttributeBinding(attribute->name);
2002
2003 if (location != -1) // Set by glBindAttribLocation
2004 {
2005 if (!mLinkedAttribute[location].name.empty())
2006 {
2007 // Multiple active attributes bound to the same location; not an error
2008 }
2009
2010 mLinkedAttribute[location] = *attribute;
2011
2012 int rows = VariableRowCount(attribute->type);
2013
2014 if (rows + location > MAX_VERTEX_ATTRIBS)
2015 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002016 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 +00002017
2018 return false;
2019 }
2020
2021 for (int i = 0; i < rows; i++)
2022 {
2023 usedLocations |= 1 << (location + i);
2024 }
2025 }
2026 }
2027
2028 // Link attributes that don't have a binding location
2029 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2030 {
2031 int location = attributeBindings.getAttributeBinding(attribute->name);
2032
2033 if (location == -1) // Not set by glBindAttribLocation
2034 {
2035 int rows = VariableRowCount(attribute->type);
2036 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2037
2038 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2039 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002040 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002041
2042 return false; // Fail to link
2043 }
2044
2045 mLinkedAttribute[availableIndex] = *attribute;
2046 }
2047 }
2048
2049 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2050 {
2051 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
2052 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
2053
2054 for (int r = 0; r < rows; r++)
2055 {
2056 mSemanticIndex[attributeIndex++] = index++;
2057 }
2058 }
2059
2060 return true;
2061}
2062
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002063bool ProgramBinary::linkUniforms(InfoLog &infoLog, GLenum shader, D3DConstantTable *constantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002064{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002065 for (unsigned int constantIndex = 0; constantIndex < constantTable->constants(); constantIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002066 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002067 const D3DConstant *constant = constantTable->getConstant(constantIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002068
daniel@transgaming.com59d9ab12012-11-28 20:58:14 +00002069 if (!defineUniform(infoLog, shader, constant, "", mConstantTableVS, mConstantTablePS))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002070 {
2071 return false;
2072 }
2073 }
2074
2075 return true;
2076}
2077
2078// Adds the description of a constant found in the binary shader to the list of uniforms
2079// Returns true if succesful (uniform not already defined)
daniel@transgaming.com59d9ab12012-11-28 20:58:14 +00002080bool ProgramBinary::defineUniform(InfoLog &infoLog, GLenum shader, const D3DConstant *constant, const std::string &name,
2081 D3DConstantTable *vsConstantTable, D3DConstantTable *psConstantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002082{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002083 if (constant->registerSet == D3DConstant::RS_SAMPLER)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002084 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002085 for (unsigned int i = 0; i < constant->registerCount; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002086 {
daniel@transgaming.com59d9ab12012-11-28 20:58:14 +00002087 const D3DConstant *psConstant = psConstantTable->getConstantByName(constant->name.c_str());
2088 const D3DConstant *vsConstant = vsConstantTable->getConstantByName(constant->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002089
2090 if (psConstant)
2091 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002092 unsigned int samplerIndex = psConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002093
2094 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2095 {
2096 mSamplersPS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002097 mSamplersPS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002098 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2099 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2100 }
2101 else
2102 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002103 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002104 return false;
2105 }
2106 }
2107
2108 if (vsConstant)
2109 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002110 unsigned int samplerIndex = vsConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002111
2112 if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
2113 {
2114 mSamplersVS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002115 mSamplersVS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002116 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2117 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2118 }
2119 else
2120 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002121 infoLog.append("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002122 return false;
2123 }
2124 }
2125 }
2126 }
2127
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002128 switch(constant->typeClass)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002129 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002130 case D3DConstant::CLASS_STRUCT:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002131 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002132 for (unsigned int arrayIndex = 0; arrayIndex < constant->elements; arrayIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002133 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002134 for (unsigned int field = 0; field < constant->structMembers[arrayIndex].size(); field++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002135 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002136 const D3DConstant *fieldConstant = constant->structMembers[arrayIndex][field];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002137
apatrick@chromium.org85fee292012-09-06 00:43:06 +00002138 std::string structIndex = (constant->elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002139
daniel@transgaming.com59d9ab12012-11-28 20:58:14 +00002140 if (!defineUniform(infoLog, shader, fieldConstant, name + constant->name + structIndex + ".", vsConstantTable, psConstantTable))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002141 {
2142 return false;
2143 }
2144 }
2145 }
2146
2147 return true;
2148 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002149 case D3DConstant::CLASS_SCALAR:
2150 case D3DConstant::CLASS_VECTOR:
2151 case D3DConstant::CLASS_MATRIX_COLUMNS:
2152 case D3DConstant::CLASS_OBJECT:
2153 return defineUniform(shader, constant, name + constant->name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002154 default:
2155 UNREACHABLE();
2156 return false;
2157 }
2158}
2159
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002160bool ProgramBinary::defineUniform(GLenum shader, const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002161{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002162 Uniform *uniform = createUniform(constant, _name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002163
2164 if(!uniform)
2165 {
2166 return false;
2167 }
2168
2169 // Check if already defined
2170 GLint location = getUniformLocation(uniform->name);
2171 GLenum type = uniform->type;
2172
2173 if (location >= 0)
2174 {
2175 delete uniform;
2176 uniform = mUniforms[mUniformIndex[location].index];
2177 }
2178
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002179 if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constant);
2180 if (shader == GL_VERTEX_SHADER) uniform->vs.set(constant);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002181
2182 if (location >= 0)
2183 {
2184 return uniform->type == type;
2185 }
2186
2187 mUniforms.push_back(uniform);
2188 unsigned int uniformIndex = mUniforms.size() - 1;
2189
2190 for (unsigned int i = 0; i < uniform->arraySize; ++i)
2191 {
2192 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
2193 }
2194
2195 return true;
2196}
2197
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002198Uniform *ProgramBinary::createUniform(const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002199{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002200 if (constant->rows == 1) // Vectors and scalars
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002201 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002202 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002203 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002204 case D3DConstant::PT_SAMPLER2D:
2205 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002206 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002207 case 1: return new Uniform(GL_SAMPLER_2D, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002208 default: UNREACHABLE();
2209 }
2210 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002211 case D3DConstant::PT_SAMPLERCUBE:
2212 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002213 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002214 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002215 default: UNREACHABLE();
2216 }
2217 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002218 case D3DConstant::PT_BOOL:
2219 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002220 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002221 case 1: return new Uniform(GL_BOOL, _name, constant->elements);
2222 case 2: return new Uniform(GL_BOOL_VEC2, _name, constant->elements);
2223 case 3: return new Uniform(GL_BOOL_VEC3, _name, constant->elements);
2224 case 4: return new Uniform(GL_BOOL_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002225 default: UNREACHABLE();
2226 }
2227 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002228 case D3DConstant::PT_INT:
2229 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002230 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002231 case 1: return new Uniform(GL_INT, _name, constant->elements);
2232 case 2: return new Uniform(GL_INT_VEC2, _name, constant->elements);
2233 case 3: return new Uniform(GL_INT_VEC3, _name, constant->elements);
2234 case 4: return new Uniform(GL_INT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002235 default: UNREACHABLE();
2236 }
2237 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002238 case D3DConstant::PT_FLOAT:
2239 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002240 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002241 case 1: return new Uniform(GL_FLOAT, _name, constant->elements);
2242 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constant->elements);
2243 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constant->elements);
2244 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002245 default: UNREACHABLE();
2246 }
2247 break;
2248 default:
2249 UNREACHABLE();
2250 }
2251 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002252 else if (constant->rows == constant->columns) // Square matrices
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002253 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002254 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002255 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002256 case D3DConstant::PT_FLOAT:
2257 switch (constant->rows)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002258 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002259 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constant->elements);
2260 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constant->elements);
2261 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002262 default: UNREACHABLE();
2263 }
2264 break;
2265 default: UNREACHABLE();
2266 }
2267 }
2268 else UNREACHABLE();
2269
2270 return 0;
2271}
2272
2273// This method needs to match OutputHLSL::decorate
2274std::string ProgramBinary::decorateAttribute(const std::string &name)
2275{
2276 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2277 {
2278 return "_" + name;
2279 }
2280
2281 return name;
2282}
2283
2284std::string ProgramBinary::undecorateUniform(const std::string &_name)
2285{
2286 std::string name = _name;
2287
2288 // Remove any structure field decoration
2289 size_t pos = 0;
2290 while ((pos = name.find("._", pos)) != std::string::npos)
2291 {
2292 name.replace(pos, 2, ".");
2293 }
2294
2295 // Remove the leading decoration
2296 if (name[0] == '_')
2297 {
2298 return name.substr(1);
2299 }
2300 else if (name.compare(0, 3, "ar_") == 0)
2301 {
2302 return name.substr(3);
2303 }
2304
2305 return name;
2306}
2307
2308void ProgramBinary::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
2309{
2310 float vector[D3D9_MAX_FLOAT_CONSTANTS * 4];
2311 BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS];
2312
2313 if (targetUniform->ps.float4Index >= 0 || targetUniform->vs.float4Index >= 0)
2314 {
2315 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2316 for (int i = 0; i < count; i++)
2317 {
2318 for (int j = 0; j < 4; j++)
2319 {
2320 if (j < width)
2321 {
2322 vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f;
2323 }
2324 else
2325 {
2326 vector[i * 4 + j] = 0.0f;
2327 }
2328 }
2329 }
2330 }
2331
2332 if (targetUniform->ps.boolIndex >= 0 || targetUniform->vs.boolIndex >= 0)
2333 {
2334 int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0;
2335 int vsCount = targetUniform->vs.boolIndex >= 0 ? targetUniform->vs.registerCount : 0;
2336 int copyCount = std::min(count * width, std::max(psCount, vsCount));
2337 ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS);
2338 for (int i = 0; i < copyCount; i++)
2339 {
2340 boolVector[i] = v[i] != GL_FALSE;
2341 }
2342 }
2343
2344 if (targetUniform->ps.float4Index >= 0)
2345 {
2346 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount);
2347 }
2348
2349 if (targetUniform->ps.boolIndex >= 0)
2350 {
2351 mDevice->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount);
2352 }
2353
2354 if (targetUniform->vs.float4Index >= 0)
2355 {
2356 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount);
2357 }
2358
2359 if (targetUniform->vs.boolIndex >= 0)
2360 {
2361 mDevice->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount);
2362 }
2363}
2364
2365bool ProgramBinary::applyUniformnfv(Uniform *targetUniform, const GLfloat *v)
2366{
2367 if (targetUniform->ps.registerCount)
2368 {
2369 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount);
2370 }
2371
2372 if (targetUniform->vs.registerCount)
2373 {
2374 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount);
2375 }
2376
2377 return true;
2378}
2379
2380bool ProgramBinary::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2381{
2382 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002383 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002384
2385 for (int i = 0; i < count; i++)
2386 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002387 vector[i] = Vector4((float)v[i], 0, 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002388 }
2389
2390 if (targetUniform->ps.registerCount)
2391 {
2392 if (targetUniform->ps.samplerIndex >= 0)
2393 {
2394 unsigned int firstIndex = targetUniform->ps.samplerIndex;
2395
2396 for (int i = 0; i < count; i++)
2397 {
2398 unsigned int samplerIndex = firstIndex + i;
2399
2400 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2401 {
2402 ASSERT(mSamplersPS[samplerIndex].active);
2403 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
2404 }
2405 }
2406 }
2407 else
2408 {
2409 ASSERT(targetUniform->ps.float4Index >= 0);
2410 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount);
2411 }
2412 }
2413
2414 if (targetUniform->vs.registerCount)
2415 {
2416 if (targetUniform->vs.samplerIndex >= 0)
2417 {
2418 unsigned int firstIndex = targetUniform->vs.samplerIndex;
2419
2420 for (int i = 0; i < count; i++)
2421 {
2422 unsigned int samplerIndex = firstIndex + i;
2423
2424 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2425 {
2426 ASSERT(mSamplersVS[samplerIndex].active);
2427 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2428 }
2429 }
2430 }
2431 else
2432 {
2433 ASSERT(targetUniform->vs.float4Index >= 0);
2434 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2435 }
2436 }
2437
2438 return true;
2439}
2440
2441bool ProgramBinary::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2442{
2443 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002444 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002445
2446 for (int i = 0; i < count; i++)
2447 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002448 vector[i] = Vector4((float)v[0], (float)v[1], 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002449
2450 v += 2;
2451 }
2452
2453 applyUniformniv(targetUniform, count, vector);
2454
2455 return true;
2456}
2457
2458bool ProgramBinary::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2459{
2460 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002461 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002462
2463 for (int i = 0; i < count; i++)
2464 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002465 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002466
2467 v += 3;
2468 }
2469
2470 applyUniformniv(targetUniform, count, vector);
2471
2472 return true;
2473}
2474
2475bool ProgramBinary::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2476{
2477 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002478 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002479
2480 for (int i = 0; i < count; i++)
2481 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002482 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002483
2484 v += 4;
2485 }
2486
2487 applyUniformniv(targetUniform, count, vector);
2488
2489 return true;
2490}
2491
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002492void ProgramBinary::applyUniformniv(Uniform *targetUniform, GLsizei count, const Vector4 *vector)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002493{
2494 if (targetUniform->ps.registerCount)
2495 {
2496 ASSERT(targetUniform->ps.float4Index >= 0);
2497 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount);
2498 }
2499
2500 if (targetUniform->vs.registerCount)
2501 {
2502 ASSERT(targetUniform->vs.float4Index >= 0);
2503 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2504 }
2505}
2506
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002507bool ProgramBinary::isValidated() const
2508{
2509 return mValidated;
2510}
2511
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002512void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2513{
2514 // Skip over inactive attributes
2515 unsigned int activeAttribute = 0;
2516 unsigned int attribute;
2517 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2518 {
2519 if (mLinkedAttribute[attribute].name.empty())
2520 {
2521 continue;
2522 }
2523
2524 if (activeAttribute == index)
2525 {
2526 break;
2527 }
2528
2529 activeAttribute++;
2530 }
2531
2532 if (bufsize > 0)
2533 {
2534 const char *string = mLinkedAttribute[attribute].name.c_str();
2535
2536 strncpy(name, string, bufsize);
2537 name[bufsize - 1] = '\0';
2538
2539 if (length)
2540 {
2541 *length = strlen(name);
2542 }
2543 }
2544
2545 *size = 1; // Always a single 'type' instance
2546
2547 *type = mLinkedAttribute[attribute].type;
2548}
2549
2550GLint ProgramBinary::getActiveAttributeCount()
2551{
2552 int count = 0;
2553
2554 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2555 {
2556 if (!mLinkedAttribute[attributeIndex].name.empty())
2557 {
2558 count++;
2559 }
2560 }
2561
2562 return count;
2563}
2564
2565GLint ProgramBinary::getActiveAttributeMaxLength()
2566{
2567 int maxLength = 0;
2568
2569 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2570 {
2571 if (!mLinkedAttribute[attributeIndex].name.empty())
2572 {
2573 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2574 }
2575 }
2576
2577 return maxLength;
2578}
2579
2580void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2581{
2582 // Skip over internal uniforms
2583 unsigned int activeUniform = 0;
2584 unsigned int uniform;
2585 for (uniform = 0; uniform < mUniforms.size(); uniform++)
2586 {
2587 if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0)
2588 {
2589 continue;
2590 }
2591
2592 if (activeUniform == index)
2593 {
2594 break;
2595 }
2596
2597 activeUniform++;
2598 }
2599
2600 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2601
2602 if (bufsize > 0)
2603 {
2604 std::string string = mUniforms[uniform]->name;
2605
2606 if (mUniforms[uniform]->isArray())
2607 {
2608 string += "[0]";
2609 }
2610
2611 strncpy(name, string.c_str(), bufsize);
2612 name[bufsize - 1] = '\0';
2613
2614 if (length)
2615 {
2616 *length = strlen(name);
2617 }
2618 }
2619
2620 *size = mUniforms[uniform]->arraySize;
2621
2622 *type = mUniforms[uniform]->type;
2623}
2624
2625GLint ProgramBinary::getActiveUniformCount()
2626{
2627 int count = 0;
2628
2629 unsigned int numUniforms = mUniforms.size();
2630 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2631 {
2632 if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2633 {
2634 count++;
2635 }
2636 }
2637
2638 return count;
2639}
2640
2641GLint ProgramBinary::getActiveUniformMaxLength()
2642{
2643 int maxLength = 0;
2644
2645 unsigned int numUniforms = mUniforms.size();
2646 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2647 {
2648 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2649 {
2650 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2651 if (mUniforms[uniformIndex]->isArray())
2652 {
2653 length += 3; // Counting in "[0]".
2654 }
2655 maxLength = std::max(length, maxLength);
2656 }
2657 }
2658
2659 return maxLength;
2660}
2661
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002662void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002663{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002664 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002665 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002666 {
2667 mValidated = false;
2668 }
2669 else
2670 {
2671 mValidated = true;
2672 }
2673}
2674
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002675bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002676{
2677 // if any two active samplers in a program are of different types, but refer to the same
2678 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2679 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2680
2681 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
2682 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2683
2684 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2685 {
2686 textureUnitType[i] = TEXTURE_UNKNOWN;
2687 }
2688
2689 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2690 {
2691 if (mSamplersPS[i].active)
2692 {
2693 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2694
2695 if (unit >= maxCombinedTextureImageUnits)
2696 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002697 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002698 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002699 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002700 }
2701
2702 return false;
2703 }
2704
2705 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2706 {
2707 if (mSamplersPS[i].textureType != textureUnitType[unit])
2708 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002709 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002710 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002711 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002712 }
2713
2714 return false;
2715 }
2716 }
2717 else
2718 {
2719 textureUnitType[unit] = mSamplersPS[i].textureType;
2720 }
2721 }
2722 }
2723
2724 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2725 {
2726 if (mSamplersVS[i].active)
2727 {
2728 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2729
2730 if (unit >= maxCombinedTextureImageUnits)
2731 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002732 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002733 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002734 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002735 }
2736
2737 return false;
2738 }
2739
2740 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2741 {
2742 if (mSamplersVS[i].textureType != textureUnitType[unit])
2743 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002744 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002745 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002746 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002747 }
2748
2749 return false;
2750 }
2751 }
2752 else
2753 {
2754 textureUnitType[unit] = mSamplersVS[i].textureType;
2755 }
2756 }
2757 }
2758
2759 return true;
2760}
2761
2762GLint ProgramBinary::getDxDepthRangeLocation() const
2763{
2764 return mDxDepthRangeLocation;
2765}
2766
2767GLint ProgramBinary::getDxDepthLocation() const
2768{
2769 return mDxDepthLocation;
2770}
2771
2772GLint ProgramBinary::getDxCoordLocation() const
2773{
2774 return mDxCoordLocation;
2775}
2776
2777GLint ProgramBinary::getDxHalfPixelSizeLocation() const
2778{
2779 return mDxHalfPixelSizeLocation;
2780}
2781
2782GLint ProgramBinary::getDxFrontCCWLocation() const
2783{
2784 return mDxFrontCCWLocation;
2785}
2786
2787GLint ProgramBinary::getDxPointsOrLinesLocation() const
2788{
2789 return mDxPointsOrLinesLocation;
2790}
2791
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002792ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2793{
2794}
2795
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002796}