blob: bcff2984eb577aa06a75750fc8d1d879423f83a5 [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
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000022namespace gl
23{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000024std::string str(int i)
25{
26 char buffer[20];
27 snprintf(buffer, sizeof(buffer), "%d", i);
28 return buffer;
29}
30
31Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize)
32 : type(type), _name(_name), name(ProgramBinary::undecorateUniform(_name)), arraySize(arraySize)
33{
34 int bytes = UniformInternalSize(type) * arraySize;
35 data = new unsigned char[bytes];
36 memset(data, 0, bytes);
37 dirty = true;
38}
39
40Uniform::~Uniform()
41{
42 delete[] data;
43}
44
45bool Uniform::isArray()
46{
daniel@transgaming.com22ba0f72012-09-27 17:46:04 +000047 size_t dot = _name.find_last_of('.');
48 if (dot == std::string::npos) dot = -1;
49
50 return _name.compare(dot + 1, dot + 4, "ar_") == 0;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000051}
52
53UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index)
54 : name(ProgramBinary::undecorateUniform(_name)), element(element), index(index)
55{
56}
57
daniel@transgaming.come87ca002012-07-24 18:30:43 +000058unsigned int ProgramBinary::mCurrentSerial = 1;
59
daniel@transgaming.com70062c92012-11-28 19:32:30 +000060ProgramBinary::ProgramBinary(rx::Renderer *renderer) : RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000061{
daniel@transgaming.com70062c92012-11-28 19:32:30 +000062 ASSERT(dynamic_cast<rx::Renderer9*>(renderer) != NULL); // D3D9_REPLACE
63 mRenderer = static_cast<rx::Renderer9*>(renderer);
daniel@transgaming.come4733d72012-10-31 18:07:01 +000064 mDevice = mRenderer->getDevice(); // D3D9_REPLACE
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000065
66 mPixelExecutable = NULL;
67 mVertexExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000068
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000069 mValidated = false;
70
71 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
72 {
73 mSemanticIndex[index] = -1;
74 }
75
76 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
77 {
78 mSamplersPS[index].active = false;
79 }
80
81 for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
82 {
83 mSamplersVS[index].active = false;
84 }
85
86 mUsedVertexSamplerRange = 0;
87 mUsedPixelSamplerRange = 0;
88
89 mDxDepthRangeLocation = -1;
90 mDxDepthLocation = -1;
91 mDxCoordLocation = -1;
92 mDxHalfPixelSizeLocation = -1;
93 mDxFrontCCWLocation = -1;
94 mDxPointsOrLinesLocation = -1;
95}
96
97ProgramBinary::~ProgramBinary()
98{
daniel@transgaming.com95892412012-11-28 20:59:09 +000099 delete mPixelExecutable;
100 delete mVertexExecutable;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000101
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000102 while (!mUniforms.empty())
103 {
104 delete mUniforms.back();
105 mUniforms.pop_back();
106 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000107}
108
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000109unsigned int ProgramBinary::getSerial() const
110{
111 return mSerial;
112}
113
114unsigned int ProgramBinary::issueSerial()
115{
116 return mCurrentSerial++;
117}
118
daniel@transgaming.com95892412012-11-28 20:59:09 +0000119rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000120{
121 return mPixelExecutable;
122}
123
daniel@transgaming.com95892412012-11-28 20:59:09 +0000124rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000125{
126 return mVertexExecutable;
127}
128
129GLuint ProgramBinary::getAttributeLocation(const char *name)
130{
131 if (name)
132 {
133 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
134 {
135 if (mLinkedAttribute[index].name == std::string(name))
136 {
137 return index;
138 }
139 }
140 }
141
142 return -1;
143}
144
145int ProgramBinary::getSemanticIndex(int attributeIndex)
146{
147 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
148
149 return mSemanticIndex[attributeIndex];
150}
151
152// Returns one more than the highest sampler index used.
153GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
154{
155 switch (type)
156 {
157 case SAMPLER_PIXEL:
158 return mUsedPixelSamplerRange;
159 case SAMPLER_VERTEX:
160 return mUsedVertexSamplerRange;
161 default:
162 UNREACHABLE();
163 return 0;
164 }
165}
166
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000167bool ProgramBinary::usesPointSize() const
168{
169 return mUsesPointSize;
170}
171
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000172// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
173// index (0-15 for the pixel shader and 0-3 for the vertex shader).
174GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
175{
176 GLint logicalTextureUnit = -1;
177
178 switch (type)
179 {
180 case SAMPLER_PIXEL:
181 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
182
183 if (mSamplersPS[samplerIndex].active)
184 {
185 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
186 }
187 break;
188 case SAMPLER_VERTEX:
189 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
190
191 if (mSamplersVS[samplerIndex].active)
192 {
193 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
194 }
195 break;
196 default: UNREACHABLE();
197 }
198
199 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)getContext()->getMaximumCombinedTextureImageUnits())
200 {
201 return logicalTextureUnit;
202 }
203
204 return -1;
205}
206
207// Returns the texture type for a given Direct3D 9 sampler type and
208// index (0-15 for the pixel shader and 0-3 for the vertex shader).
209TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
210{
211 switch (type)
212 {
213 case SAMPLER_PIXEL:
214 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
215 ASSERT(mSamplersPS[samplerIndex].active);
216 return mSamplersPS[samplerIndex].textureType;
217 case SAMPLER_VERTEX:
218 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
219 ASSERT(mSamplersVS[samplerIndex].active);
220 return mSamplersVS[samplerIndex].textureType;
221 default: UNREACHABLE();
222 }
223
224 return TEXTURE_2D;
225}
226
227GLint ProgramBinary::getUniformLocation(std::string name)
228{
229 unsigned int subscript = 0;
230
231 // Strip any trailing array operator and retrieve the subscript
232 size_t open = name.find_last_of('[');
233 size_t close = name.find_last_of(']');
234 if (open != std::string::npos && close == name.length() - 1)
235 {
236 subscript = atoi(name.substr(open + 1).c_str());
237 name.erase(open);
238 }
239
240 unsigned int numUniforms = mUniformIndex.size();
241 for (unsigned int location = 0; location < numUniforms; location++)
242 {
243 if (mUniformIndex[location].name == name &&
244 mUniformIndex[location].element == subscript)
245 {
246 return location;
247 }
248 }
249
250 return -1;
251}
252
253bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
254{
255 if (location < 0 || location >= (int)mUniformIndex.size())
256 {
257 return false;
258 }
259
260 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
261 targetUniform->dirty = true;
262
263 if (targetUniform->type == GL_FLOAT)
264 {
265 int arraySize = targetUniform->arraySize;
266
267 if (arraySize == 1 && count > 1)
268 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
269
270 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
271
272 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
273
274 for (int i = 0; i < count; i++)
275 {
276 target[0] = v[0];
277 target[1] = 0;
278 target[2] = 0;
279 target[3] = 0;
280 target += 4;
281 v += 1;
282 }
283 }
284 else if (targetUniform->type == GL_BOOL)
285 {
286 int arraySize = targetUniform->arraySize;
287
288 if (arraySize == 1 && count > 1)
289 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
290
291 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
292 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
293
294 for (int i = 0; i < count; ++i)
295 {
296 if (v[i] == 0.0f)
297 {
298 boolParams[i] = GL_FALSE;
299 }
300 else
301 {
302 boolParams[i] = GL_TRUE;
303 }
304 }
305 }
306 else
307 {
308 return false;
309 }
310
311 return true;
312}
313
314bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
315{
316 if (location < 0 || location >= (int)mUniformIndex.size())
317 {
318 return false;
319 }
320
321 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
322 targetUniform->dirty = true;
323
324 if (targetUniform->type == GL_FLOAT_VEC2)
325 {
326 int arraySize = targetUniform->arraySize;
327
328 if (arraySize == 1 && count > 1)
329 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
330
331 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
332
333 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
334
335 for (int i = 0; i < count; i++)
336 {
337 target[0] = v[0];
338 target[1] = v[1];
339 target[2] = 0;
340 target[3] = 0;
341 target += 4;
342 v += 2;
343 }
344 }
345 else if (targetUniform->type == GL_BOOL_VEC2)
346 {
347 int arraySize = targetUniform->arraySize;
348
349 if (arraySize == 1 && count > 1)
350 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
351
352 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
353
354 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
355
356 for (int i = 0; i < count * 2; ++i)
357 {
358 if (v[i] == 0.0f)
359 {
360 boolParams[i] = GL_FALSE;
361 }
362 else
363 {
364 boolParams[i] = GL_TRUE;
365 }
366 }
367 }
368 else
369 {
370 return false;
371 }
372
373 return true;
374}
375
376bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
377{
378 if (location < 0 || location >= (int)mUniformIndex.size())
379 {
380 return false;
381 }
382
383 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
384 targetUniform->dirty = true;
385
386 if (targetUniform->type == GL_FLOAT_VEC3)
387 {
388 int arraySize = targetUniform->arraySize;
389
390 if (arraySize == 1 && count > 1)
391 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
392
393 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
394
395 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
396
397 for (int i = 0; i < count; i++)
398 {
399 target[0] = v[0];
400 target[1] = v[1];
401 target[2] = v[2];
402 target[3] = 0;
403 target += 4;
404 v += 3;
405 }
406 }
407 else if (targetUniform->type == GL_BOOL_VEC3)
408 {
409 int arraySize = targetUniform->arraySize;
410
411 if (arraySize == 1 && count > 1)
412 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
413
414 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
415 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
416
417 for (int i = 0; i < count * 3; ++i)
418 {
419 if (v[i] == 0.0f)
420 {
421 boolParams[i] = GL_FALSE;
422 }
423 else
424 {
425 boolParams[i] = GL_TRUE;
426 }
427 }
428 }
429 else
430 {
431 return false;
432 }
433
434 return true;
435}
436
437bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
438{
439 if (location < 0 || location >= (int)mUniformIndex.size())
440 {
441 return false;
442 }
443
444 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
445 targetUniform->dirty = true;
446
447 if (targetUniform->type == GL_FLOAT_VEC4)
448 {
449 int arraySize = targetUniform->arraySize;
450
451 if (arraySize == 1 && count > 1)
452 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
453
454 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
455
456 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
457 v, 4 * sizeof(GLfloat) * count);
458 }
459 else if (targetUniform->type == GL_BOOL_VEC4)
460 {
461 int arraySize = targetUniform->arraySize;
462
463 if (arraySize == 1 && count > 1)
464 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
465
466 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
467 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
468
469 for (int i = 0; i < count * 4; ++i)
470 {
471 if (v[i] == 0.0f)
472 {
473 boolParams[i] = GL_FALSE;
474 }
475 else
476 {
477 boolParams[i] = GL_TRUE;
478 }
479 }
480 }
481 else
482 {
483 return false;
484 }
485
486 return true;
487}
488
489template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
490void transposeMatrix(T *target, const GLfloat *value)
491{
492 int copyWidth = std::min(targetWidth, srcWidth);
493 int copyHeight = std::min(targetHeight, srcHeight);
494
495 for (int x = 0; x < copyWidth; x++)
496 {
497 for (int y = 0; y < copyHeight; y++)
498 {
499 target[x * targetWidth + y] = (T)value[y * srcWidth + x];
500 }
501 }
502 // clear unfilled right side
503 for (int y = 0; y < copyHeight; y++)
504 {
505 for (int x = srcWidth; x < targetWidth; x++)
506 {
507 target[y * targetWidth + x] = (T)0;
508 }
509 }
510 // clear unfilled bottom.
511 for (int y = srcHeight; y < targetHeight; y++)
512 {
513 for (int x = 0; x < targetWidth; x++)
514 {
515 target[y * targetWidth + x] = (T)0;
516 }
517 }
518}
519
520bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
521{
522 if (location < 0 || location >= (int)mUniformIndex.size())
523 {
524 return false;
525 }
526
527 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
528 targetUniform->dirty = true;
529
530 if (targetUniform->type != GL_FLOAT_MAT2)
531 {
532 return false;
533 }
534
535 int arraySize = targetUniform->arraySize;
536
537 if (arraySize == 1 && count > 1)
538 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
539
540 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
541
542 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
543 for (int i = 0; i < count; i++)
544 {
545 transposeMatrix<GLfloat,4,2,2,2>(target, value);
546 target += 8;
547 value += 4;
548 }
549
550 return true;
551}
552
553bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
554{
555 if (location < 0 || location >= (int)mUniformIndex.size())
556 {
557 return false;
558 }
559
560 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
561 targetUniform->dirty = true;
562
563 if (targetUniform->type != GL_FLOAT_MAT3)
564 {
565 return false;
566 }
567
568 int arraySize = targetUniform->arraySize;
569
570 if (arraySize == 1 && count > 1)
571 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
572
573 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
574
575 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
576 for (int i = 0; i < count; i++)
577 {
578 transposeMatrix<GLfloat,4,3,3,3>(target, value);
579 target += 12;
580 value += 9;
581 }
582
583 return true;
584}
585
586
587bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
588{
589 if (location < 0 || location >= (int)mUniformIndex.size())
590 {
591 return false;
592 }
593
594 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
595 targetUniform->dirty = true;
596
597 if (targetUniform->type != GL_FLOAT_MAT4)
598 {
599 return false;
600 }
601
602 int arraySize = targetUniform->arraySize;
603
604 if (arraySize == 1 && count > 1)
605 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
606
607 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
608
609 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
610 for (int i = 0; i < count; i++)
611 {
612 transposeMatrix<GLfloat,4,4,4,4>(target, value);
613 target += 16;
614 value += 16;
615 }
616
617 return true;
618}
619
620bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
621{
622 if (location < 0 || location >= (int)mUniformIndex.size())
623 {
624 return false;
625 }
626
627 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
628 targetUniform->dirty = true;
629
630 if (targetUniform->type == GL_INT ||
631 targetUniform->type == GL_SAMPLER_2D ||
632 targetUniform->type == GL_SAMPLER_CUBE)
633 {
634 int arraySize = targetUniform->arraySize;
635
636 if (arraySize == 1 && count > 1)
637 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
638
639 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
640
641 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
642 v, sizeof(GLint) * count);
643 }
644 else if (targetUniform->type == GL_BOOL)
645 {
646 int arraySize = targetUniform->arraySize;
647
648 if (arraySize == 1 && count > 1)
649 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
650
651 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
652 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
653
654 for (int i = 0; i < count; ++i)
655 {
656 if (v[i] == 0)
657 {
658 boolParams[i] = GL_FALSE;
659 }
660 else
661 {
662 boolParams[i] = GL_TRUE;
663 }
664 }
665 }
666 else
667 {
668 return false;
669 }
670
671 return true;
672}
673
674bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
675{
676 if (location < 0 || location >= (int)mUniformIndex.size())
677 {
678 return false;
679 }
680
681 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
682 targetUniform->dirty = true;
683
684 if (targetUniform->type == GL_INT_VEC2)
685 {
686 int arraySize = targetUniform->arraySize;
687
688 if (arraySize == 1 && count > 1)
689 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
690
691 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
692
693 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
694 v, 2 * sizeof(GLint) * count);
695 }
696 else if (targetUniform->type == GL_BOOL_VEC2)
697 {
698 int arraySize = targetUniform->arraySize;
699
700 if (arraySize == 1 && count > 1)
701 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
702
703 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
704 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
705
706 for (int i = 0; i < count * 2; ++i)
707 {
708 if (v[i] == 0)
709 {
710 boolParams[i] = GL_FALSE;
711 }
712 else
713 {
714 boolParams[i] = GL_TRUE;
715 }
716 }
717 }
718 else
719 {
720 return false;
721 }
722
723 return true;
724}
725
726bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
727{
728 if (location < 0 || location >= (int)mUniformIndex.size())
729 {
730 return false;
731 }
732
733 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
734 targetUniform->dirty = true;
735
736 if (targetUniform->type == GL_INT_VEC3)
737 {
738 int arraySize = targetUniform->arraySize;
739
740 if (arraySize == 1 && count > 1)
741 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
742
743 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
744
745 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
746 v, 3 * sizeof(GLint) * count);
747 }
748 else if (targetUniform->type == GL_BOOL_VEC3)
749 {
750 int arraySize = targetUniform->arraySize;
751
752 if (arraySize == 1 && count > 1)
753 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
754
755 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
756 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
757
758 for (int i = 0; i < count * 3; ++i)
759 {
760 if (v[i] == 0)
761 {
762 boolParams[i] = GL_FALSE;
763 }
764 else
765 {
766 boolParams[i] = GL_TRUE;
767 }
768 }
769 }
770 else
771 {
772 return false;
773 }
774
775 return true;
776}
777
778bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
779{
780 if (location < 0 || location >= (int)mUniformIndex.size())
781 {
782 return false;
783 }
784
785 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
786 targetUniform->dirty = true;
787
788 if (targetUniform->type == GL_INT_VEC4)
789 {
790 int arraySize = targetUniform->arraySize;
791
792 if (arraySize == 1 && count > 1)
793 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
794
795 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
796
797 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
798 v, 4 * sizeof(GLint) * count);
799 }
800 else if (targetUniform->type == GL_BOOL_VEC4)
801 {
802 int arraySize = targetUniform->arraySize;
803
804 if (arraySize == 1 && count > 1)
805 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
806
807 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
808 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
809
810 for (int i = 0; i < count * 4; ++i)
811 {
812 if (v[i] == 0)
813 {
814 boolParams[i] = GL_FALSE;
815 }
816 else
817 {
818 boolParams[i] = GL_TRUE;
819 }
820 }
821 }
822 else
823 {
824 return false;
825 }
826
827 return true;
828}
829
830bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
831{
832 if (location < 0 || location >= (int)mUniformIndex.size())
833 {
834 return false;
835 }
836
837 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
838
839 // sized queries -- ensure the provided buffer is large enough
840 if (bufSize)
841 {
842 int requiredBytes = UniformExternalSize(targetUniform->type);
843 if (*bufSize < requiredBytes)
844 {
845 return false;
846 }
847 }
848
849 switch (targetUniform->type)
850 {
851 case GL_FLOAT_MAT2:
852 transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
853 break;
854 case GL_FLOAT_MAT3:
855 transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
856 break;
857 case GL_FLOAT_MAT4:
858 transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
859 break;
860 default:
861 {
862 unsigned int count = UniformExternalComponentCount(targetUniform->type);
863 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
864
865 switch (UniformComponentType(targetUniform->type))
866 {
867 case GL_BOOL:
868 {
869 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * internalCount;
870
871 for (unsigned int i = 0; i < count; ++i)
872 {
873 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
874 }
875 }
876 break;
877 case GL_FLOAT:
878 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLfloat),
879 count * sizeof(GLfloat));
880 break;
881 case GL_INT:
882 {
883 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * internalCount;
884
885 for (unsigned int i = 0; i < count; ++i)
886 {
887 params[i] = (float)intParams[i];
888 }
889 }
890 break;
891 default: UNREACHABLE();
892 }
893 }
894 }
895
896 return true;
897}
898
899bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
900{
901 if (location < 0 || location >= (int)mUniformIndex.size())
902 {
903 return false;
904 }
905
906 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
907
908 // sized queries -- ensure the provided buffer is large enough
909 if (bufSize)
910 {
911 int requiredBytes = UniformExternalSize(targetUniform->type);
912 if (*bufSize < requiredBytes)
913 {
914 return false;
915 }
916 }
917
918 switch (targetUniform->type)
919 {
920 case GL_FLOAT_MAT2:
921 {
922 transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
923 }
924 break;
925 case GL_FLOAT_MAT3:
926 {
927 transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
928 }
929 break;
930 case GL_FLOAT_MAT4:
931 {
932 transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
933 }
934 break;
935 default:
936 {
937 unsigned int count = UniformExternalComponentCount(targetUniform->type);
938 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
939
940 switch (UniformComponentType(targetUniform->type))
941 {
942 case GL_BOOL:
943 {
944 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * internalCount;
945
946 for (unsigned int i = 0; i < count; ++i)
947 {
948 params[i] = (GLint)boolParams[i];
949 }
950 }
951 break;
952 case GL_FLOAT:
953 {
954 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * internalCount;
955
956 for (unsigned int i = 0; i < count; ++i)
957 {
958 params[i] = (GLint)floatParams[i];
959 }
960 }
961 break;
962 case GL_INT:
963 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLint),
964 count * sizeof(GLint));
965 break;
966 default: UNREACHABLE();
967 }
968 }
969 }
970
971 return true;
972}
973
974void ProgramBinary::dirtyAllUniforms()
975{
976 unsigned int numUniforms = mUniforms.size();
977 for (unsigned int index = 0; index < numUniforms; index++)
978 {
979 mUniforms[index]->dirty = true;
980 }
981}
982
983// Applies all the uniforms set for this program object to the Direct3D 9 device
984void ProgramBinary::applyUniforms()
985{
986 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) {
987 Uniform *targetUniform = *ub;
988
989 if (targetUniform->dirty)
990 {
991 int arraySize = targetUniform->arraySize;
992 GLfloat *f = (GLfloat*)targetUniform->data;
993 GLint *i = (GLint*)targetUniform->data;
994 GLboolean *b = (GLboolean*)targetUniform->data;
995
996 switch (targetUniform->type)
997 {
998 case GL_BOOL: applyUniformnbv(targetUniform, arraySize, 1, b); break;
999 case GL_BOOL_VEC2: applyUniformnbv(targetUniform, arraySize, 2, b); break;
1000 case GL_BOOL_VEC3: applyUniformnbv(targetUniform, arraySize, 3, b); break;
1001 case GL_BOOL_VEC4: applyUniformnbv(targetUniform, arraySize, 4, b); break;
1002 case GL_FLOAT:
1003 case GL_FLOAT_VEC2:
1004 case GL_FLOAT_VEC3:
1005 case GL_FLOAT_VEC4:
1006 case GL_FLOAT_MAT2:
1007 case GL_FLOAT_MAT3:
1008 case GL_FLOAT_MAT4: applyUniformnfv(targetUniform, f); break;
1009 case GL_SAMPLER_2D:
1010 case GL_SAMPLER_CUBE:
1011 case GL_INT: applyUniform1iv(targetUniform, arraySize, i); break;
1012 case GL_INT_VEC2: applyUniform2iv(targetUniform, arraySize, i); break;
1013 case GL_INT_VEC3: applyUniform3iv(targetUniform, arraySize, i); break;
1014 case GL_INT_VEC4: applyUniform4iv(targetUniform, arraySize, i); break;
1015 default:
1016 UNREACHABLE();
1017 }
1018
1019 targetUniform->dirty = false;
1020 }
1021 }
1022}
1023
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001024// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1025// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001026int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001027{
1028 Context *context = getContext();
1029 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1030
1031 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1032 {
1033 int n = VariableRowCount(varying->type) * varying->size;
1034 int m = VariableColumnCount(varying->type);
1035 bool success = false;
1036
1037 if (m == 2 || m == 3 || m == 4)
1038 {
1039 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
1040 {
1041 bool available = true;
1042
1043 for (int y = 0; y < n && available; y++)
1044 {
1045 for (int x = 0; x < m && available; x++)
1046 {
1047 if (packing[r + y][x])
1048 {
1049 available = false;
1050 }
1051 }
1052 }
1053
1054 if (available)
1055 {
1056 varying->reg = r;
1057 varying->col = 0;
1058
1059 for (int y = 0; y < n; y++)
1060 {
1061 for (int x = 0; x < m; x++)
1062 {
1063 packing[r + y][x] = &*varying;
1064 }
1065 }
1066
1067 success = true;
1068 }
1069 }
1070
1071 if (!success && m == 2)
1072 {
1073 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
1074 {
1075 bool available = true;
1076
1077 for (int y = 0; y < n && available; y++)
1078 {
1079 for (int x = 2; x < 4 && available; x++)
1080 {
1081 if (packing[r + y][x])
1082 {
1083 available = false;
1084 }
1085 }
1086 }
1087
1088 if (available)
1089 {
1090 varying->reg = r;
1091 varying->col = 2;
1092
1093 for (int y = 0; y < n; y++)
1094 {
1095 for (int x = 2; x < 4; x++)
1096 {
1097 packing[r + y][x] = &*varying;
1098 }
1099 }
1100
1101 success = true;
1102 }
1103 }
1104 }
1105 }
1106 else if (m == 1)
1107 {
1108 int space[4] = {0};
1109
1110 for (int y = 0; y < maxVaryingVectors; y++)
1111 {
1112 for (int x = 0; x < 4; x++)
1113 {
1114 space[x] += packing[y][x] ? 0 : 1;
1115 }
1116 }
1117
1118 int column = 0;
1119
1120 for (int x = 0; x < 4; x++)
1121 {
1122 if (space[x] >= n && space[x] < space[column])
1123 {
1124 column = x;
1125 }
1126 }
1127
1128 if (space[column] >= n)
1129 {
1130 for (int r = 0; r < maxVaryingVectors; r++)
1131 {
1132 if (!packing[r][column])
1133 {
1134 varying->reg = r;
1135
1136 for (int y = r; y < r + n; y++)
1137 {
1138 packing[y][column] = &*varying;
1139 }
1140
1141 break;
1142 }
1143 }
1144
1145 varying->col = column;
1146
1147 success = true;
1148 }
1149 }
1150 else UNREACHABLE();
1151
1152 if (!success)
1153 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001154 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001155
1156 return -1;
1157 }
1158 }
1159
1160 // Return the number of used registers
1161 int registers = 0;
1162
1163 for (int r = 0; r < maxVaryingVectors; r++)
1164 {
1165 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1166 {
1167 registers++;
1168 }
1169 }
1170
1171 return registers;
1172}
1173
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001174bool ProgramBinary::linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001175{
1176 if (pixelHLSL.empty() || vertexHLSL.empty())
1177 {
1178 return false;
1179 }
1180
1181 // Reset the varying register assignments
1182 for (VaryingList::iterator fragVar = fragmentShader->mVaryings.begin(); fragVar != fragmentShader->mVaryings.end(); fragVar++)
1183 {
1184 fragVar->reg = -1;
1185 fragVar->col = -1;
1186 }
1187
1188 for (VaryingList::iterator vtxVar = vertexShader->mVaryings.begin(); vtxVar != vertexShader->mVaryings.end(); vtxVar++)
1189 {
1190 vtxVar->reg = -1;
1191 vtxVar->col = -1;
1192 }
1193
1194 // Map the varyings to the register file
1195 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001196 int registers = packVaryings(infoLog, packing, fragmentShader);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001197
1198 if (registers < 0)
1199 {
1200 return false;
1201 }
1202
1203 // Write the HLSL input/output declarations
daniel@transgaming.com9549bea2012-11-28 20:57:23 +00001204 const bool sm3 = mRenderer->getMajorShaderModel() >= 3;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001205 Context *context = getContext();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001206 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1207
1208 if (registers == maxVaryingVectors && fragmentShader->mUsesFragCoord)
1209 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001210 infoLog.append("No varying registers left to support gl_FragCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001211
1212 return false;
1213 }
1214
1215 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1216 {
1217 bool matched = false;
1218
1219 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1220 {
1221 if (output->name == input->name)
1222 {
1223 if (output->type != input->type || output->size != input->size)
1224 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001225 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 +00001226
1227 return false;
1228 }
1229
1230 output->reg = input->reg;
1231 output->col = input->col;
1232
1233 matched = true;
1234 break;
1235 }
1236 }
1237
1238 if (!matched)
1239 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001240 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001241
1242 return false;
1243 }
1244 }
1245
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001246 mUsesPointSize = vertexShader->mUsesPointSize;
1247 std::string varyingSemantic = (mUsesPointSize && sm3) ? "COLOR" : "TEXCOORD";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001248
1249 vertexHLSL += "struct VS_INPUT\n"
1250 "{\n";
1251
1252 int semanticIndex = 0;
1253 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1254 {
1255 switch (attribute->type)
1256 {
1257 case GL_FLOAT: vertexHLSL += " float "; break;
1258 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1259 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1260 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1261 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1262 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1263 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1264 default: UNREACHABLE();
1265 }
1266
1267 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1268
1269 semanticIndex += VariableRowCount(attribute->type);
1270 }
1271
1272 vertexHLSL += "};\n"
1273 "\n"
1274 "struct VS_OUTPUT\n"
1275 "{\n"
1276 " float4 gl_Position : POSITION;\n";
1277
1278 for (int r = 0; r < registers; r++)
1279 {
1280 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1281
1282 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1283 }
1284
1285 if (fragmentShader->mUsesFragCoord)
1286 {
1287 vertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1288 }
1289
1290 if (vertexShader->mUsesPointSize && sm3)
1291 {
1292 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1293 }
1294
1295 vertexHLSL += "};\n"
1296 "\n"
1297 "VS_OUTPUT main(VS_INPUT input)\n"
1298 "{\n";
1299
1300 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1301 {
1302 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1303
1304 if (VariableRowCount(attribute->type) > 1) // Matrix
1305 {
1306 vertexHLSL += "transpose";
1307 }
1308
1309 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1310 }
1311
1312 vertexHLSL += "\n"
1313 " gl_main();\n"
1314 "\n"
1315 " VS_OUTPUT output;\n"
1316 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001317 " output.gl_Position.y = -(gl_Position.y + dx_HalfPixelSize.y * gl_Position.w);\n"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001318 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1319 " output.gl_Position.w = gl_Position.w;\n";
1320
1321 if (vertexShader->mUsesPointSize && sm3)
1322 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001323 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001324 }
1325
1326 if (fragmentShader->mUsesFragCoord)
1327 {
1328 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1329 }
1330
1331 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1332 {
1333 if (varying->reg >= 0)
1334 {
1335 for (int i = 0; i < varying->size; i++)
1336 {
1337 int rows = VariableRowCount(varying->type);
1338
1339 for (int j = 0; j < rows; j++)
1340 {
1341 int r = varying->reg + i * rows + j;
1342 vertexHLSL += " output.v" + str(r);
1343
1344 bool sharedRegister = false; // Register used by multiple varyings
1345
1346 for (int x = 0; x < 4; x++)
1347 {
1348 if (packing[r][x] && packing[r][x] != packing[r][0])
1349 {
1350 sharedRegister = true;
1351 break;
1352 }
1353 }
1354
1355 if(sharedRegister)
1356 {
1357 vertexHLSL += ".";
1358
1359 for (int x = 0; x < 4; x++)
1360 {
1361 if (packing[r][x] == &*varying)
1362 {
1363 switch(x)
1364 {
1365 case 0: vertexHLSL += "x"; break;
1366 case 1: vertexHLSL += "y"; break;
1367 case 2: vertexHLSL += "z"; break;
1368 case 3: vertexHLSL += "w"; break;
1369 }
1370 }
1371 }
1372 }
1373
1374 vertexHLSL += " = " + varying->name;
1375
1376 if (varying->array)
1377 {
1378 vertexHLSL += "[" + str(i) + "]";
1379 }
1380
1381 if (rows > 1)
1382 {
1383 vertexHLSL += "[" + str(j) + "]";
1384 }
1385
1386 vertexHLSL += ";\n";
1387 }
1388 }
1389 }
1390 }
1391
1392 vertexHLSL += "\n"
1393 " return output;\n"
1394 "}\n";
1395
1396 pixelHLSL += "struct PS_INPUT\n"
1397 "{\n";
1398
1399 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1400 {
1401 if (varying->reg >= 0)
1402 {
1403 for (int i = 0; i < varying->size; i++)
1404 {
1405 int rows = VariableRowCount(varying->type);
1406 for (int j = 0; j < rows; j++)
1407 {
1408 std::string n = str(varying->reg + i * rows + j);
1409 pixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
1410 }
1411 }
1412 }
1413 else UNREACHABLE();
1414 }
1415
1416 if (fragmentShader->mUsesFragCoord)
1417 {
1418 pixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1419 if (sm3) {
1420 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1421 }
1422 }
1423
1424 if (fragmentShader->mUsesPointCoord && sm3)
1425 {
1426 pixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1427 }
1428
1429 if (fragmentShader->mUsesFrontFacing)
1430 {
1431 pixelHLSL += " float vFace : VFACE;\n";
1432 }
1433
1434 pixelHLSL += "};\n"
1435 "\n"
1436 "struct PS_OUTPUT\n"
1437 "{\n"
1438 " float4 gl_Color[1] : COLOR;\n"
1439 "};\n"
1440 "\n"
1441 "PS_OUTPUT main(PS_INPUT input)\n"
1442 "{\n";
1443
1444 if (fragmentShader->mUsesFragCoord)
1445 {
1446 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1447
1448 if (sm3)
1449 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001450 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001451 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001452 }
1453 else
1454 {
1455 // dx_Coord contains the viewport width/2, height/2, center.x and center.y. See Context::applyRenderTarget()
1456 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Coord.x + dx_Coord.z;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001457 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Coord.y + dx_Coord.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001458 }
1459
1460 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
1461 " gl_FragCoord.w = rhw;\n";
1462 }
1463
1464 if (fragmentShader->mUsesPointCoord && sm3)
1465 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001466 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1467 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001468 }
1469
1470 if (fragmentShader->mUsesFrontFacing)
1471 {
1472 pixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1473 }
1474
1475 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1476 {
1477 if (varying->reg >= 0)
1478 {
1479 for (int i = 0; i < varying->size; i++)
1480 {
1481 int rows = VariableRowCount(varying->type);
1482 for (int j = 0; j < rows; j++)
1483 {
1484 std::string n = str(varying->reg + i * rows + j);
1485 pixelHLSL += " " + varying->name;
1486
1487 if (varying->array)
1488 {
1489 pixelHLSL += "[" + str(i) + "]";
1490 }
1491
1492 if (rows > 1)
1493 {
1494 pixelHLSL += "[" + str(j) + "]";
1495 }
1496
1497 pixelHLSL += " = input.v" + n + ";\n";
1498 }
1499 }
1500 }
1501 else UNREACHABLE();
1502 }
1503
1504 pixelHLSL += "\n"
1505 " gl_main();\n"
1506 "\n"
1507 " PS_OUTPUT output;\n"
1508 " output.gl_Color[0] = gl_Color[0];\n"
1509 "\n"
1510 " return output;\n"
1511 "}\n";
1512
1513 return true;
1514}
1515
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001516bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1517{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001518 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001519
1520 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001521 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001522 if (format != GL_PROGRAM_BINARY_ANGLE)
1523 {
1524 infoLog.append("Invalid program binary format.");
1525 return false;
1526 }
1527
1528 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001529 stream.read(&version);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001530 if (version != BUILD_REVISION)
1531 {
1532 infoLog.append("Invalid program binary version.");
1533 return false;
1534 }
1535
1536 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1537 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001538 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001539 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001540 stream.read(&name);
1541 mLinkedAttribute[i].name = name;
1542 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001543 }
1544
1545 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1546 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001547 stream.read(&mSamplersPS[i].active);
1548 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001549
1550 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001551 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001552 mSamplersPS[i].textureType = (TextureType) textureType;
1553 }
1554
1555 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1556 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001557 stream.read(&mSamplersVS[i].active);
1558 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001559
1560 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001561 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001562 mSamplersVS[i].textureType = (TextureType) textureType;
1563 }
1564
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001565 stream.read(&mUsedVertexSamplerRange);
1566 stream.read(&mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001567
1568 unsigned int size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001569 stream.read(&size);
1570 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001571 {
1572 infoLog.append("Invalid program binary.");
1573 return false;
1574 }
1575
1576 mUniforms.resize(size);
1577 for (unsigned int i = 0; i < size; ++i)
1578 {
1579 GLenum type;
1580 std::string _name;
1581 unsigned int arraySize;
1582
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001583 stream.read(&type);
1584 stream.read(&_name);
1585 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001586
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001587 mUniforms[i] = new Uniform(type, _name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001588
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001589 stream.read(&mUniforms[i]->ps.float4Index);
1590 stream.read(&mUniforms[i]->ps.samplerIndex);
1591 stream.read(&mUniforms[i]->ps.boolIndex);
1592 stream.read(&mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001593
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001594 stream.read(&mUniforms[i]->vs.float4Index);
1595 stream.read(&mUniforms[i]->vs.samplerIndex);
1596 stream.read(&mUniforms[i]->vs.boolIndex);
1597 stream.read(&mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001598 }
1599
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001600 stream.read(&size);
1601 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001602 {
1603 infoLog.append("Invalid program binary.");
1604 return false;
1605 }
1606
1607 mUniformIndex.resize(size);
1608 for (unsigned int i = 0; i < size; ++i)
1609 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001610 stream.read(&mUniformIndex[i].name);
1611 stream.read(&mUniformIndex[i].element);
1612 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001613 }
1614
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001615 stream.read(&mDxDepthRangeLocation);
1616 stream.read(&mDxDepthLocation);
1617 stream.read(&mDxCoordLocation);
1618 stream.read(&mDxHalfPixelSizeLocation);
1619 stream.read(&mDxFrontCCWLocation);
1620 stream.read(&mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001621
1622 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001623 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001624
1625 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001626 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001627
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001628 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001629
daniel@transgaming.com36038542012-11-28 20:59:26 +00001630 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001631 ptr += sizeof(GUID);
1632
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001633 GUID identifier = mRenderer->getAdapterIdentifier();
1634 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001635 {
1636 infoLog.append("Invalid program binary.");
1637 return false;
1638 }
1639
1640 const char *pixelShaderFunction = ptr;
1641 ptr += pixelShaderSize;
1642
1643 const char *vertexShaderFunction = ptr;
1644 ptr += vertexShaderSize;
1645
daniel@transgaming.com95892412012-11-28 20:59:09 +00001646 rx::ShaderExecutable *executable;
1647 executable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
1648 pixelShaderSize, GL_FRAGMENT_SHADER, NULL);
1649 if (!executable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001650 {
1651 infoLog.append("Could not create pixel shader.");
1652 return false;
1653 }
daniel@transgaming.com95892412012-11-28 20:59:09 +00001654 mPixelExecutable = rx::ShaderExecutable9::makeShaderExecutable9(executable);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001655
daniel@transgaming.com95892412012-11-28 20:59:09 +00001656 executable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
1657 vertexShaderSize, GL_VERTEX_SHADER, NULL);
1658 if (!executable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001659 {
1660 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001661 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001662 mPixelExecutable = NULL;
1663 return false;
1664 }
daniel@transgaming.com95892412012-11-28 20:59:09 +00001665 mVertexExecutable = rx::ShaderExecutable9::makeShaderExecutable9(executable);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001666
1667 return true;
1668}
1669
1670bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1671{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001672 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001673
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001674 stream.write(GL_PROGRAM_BINARY_ANGLE);
1675 stream.write(BUILD_REVISION);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001676
1677 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1678 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001679 stream.write(mLinkedAttribute[i].type);
1680 stream.write(mLinkedAttribute[i].name);
1681 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001682 }
1683
1684 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1685 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001686 stream.write(mSamplersPS[i].active);
1687 stream.write(mSamplersPS[i].logicalTextureUnit);
1688 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001689 }
1690
1691 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1692 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001693 stream.write(mSamplersVS[i].active);
1694 stream.write(mSamplersVS[i].logicalTextureUnit);
1695 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001696 }
1697
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001698 stream.write(mUsedVertexSamplerRange);
1699 stream.write(mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001700
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001701 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001702 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1703 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001704 stream.write(mUniforms[i]->type);
1705 stream.write(mUniforms[i]->_name);
1706 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001707
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001708 stream.write(mUniforms[i]->ps.float4Index);
1709 stream.write(mUniforms[i]->ps.samplerIndex);
1710 stream.write(mUniforms[i]->ps.boolIndex);
1711 stream.write(mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001712
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001713 stream.write(mUniforms[i]->vs.float4Index);
1714 stream.write(mUniforms[i]->vs.samplerIndex);
1715 stream.write(mUniforms[i]->vs.boolIndex);
1716 stream.write(mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001717 }
1718
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001719 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001720 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1721 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001722 stream.write(mUniformIndex[i].name);
1723 stream.write(mUniformIndex[i].element);
1724 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001725 }
1726
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001727 stream.write(mDxDepthRangeLocation);
1728 stream.write(mDxDepthLocation);
1729 stream.write(mDxCoordLocation);
1730 stream.write(mDxHalfPixelSizeLocation);
1731 stream.write(mDxFrontCCWLocation);
1732 stream.write(mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001733
1734 UINT pixelShaderSize;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001735 HRESULT result = mPixelExecutable->getPixelShader()->GetFunction(NULL, &pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001736 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001737 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001738
1739 UINT vertexShaderSize;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001740 result = mVertexExecutable->getVertexShader()->GetFunction(NULL, &vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001741 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001742 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001743
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001744 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001745
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001746 GLsizei streamLength = stream.length();
1747 const void *streamData = stream.data();
1748
1749 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001750 if (totalLength > bufSize)
1751 {
1752 if (length)
1753 {
1754 *length = 0;
1755 }
1756
1757 return false;
1758 }
1759
1760 if (binary)
1761 {
1762 char *ptr = (char*) binary;
1763
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001764 memcpy(ptr, streamData, streamLength);
1765 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001766
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001767 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001768 ptr += sizeof(GUID);
1769
daniel@transgaming.com95892412012-11-28 20:59:09 +00001770 result = mPixelExecutable->getPixelShader()->GetFunction(ptr, &pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001771 ASSERT(SUCCEEDED(result));
1772 ptr += pixelShaderSize;
1773
daniel@transgaming.com95892412012-11-28 20:59:09 +00001774 result = mVertexExecutable->getVertexShader()->GetFunction(ptr, &vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001775 ASSERT(SUCCEEDED(result));
1776 ptr += vertexShaderSize;
1777
1778 ASSERT(ptr - totalLength == binary);
1779 }
1780
1781 if (length)
1782 {
1783 *length = totalLength;
1784 }
1785
1786 return true;
1787}
1788
1789GLint ProgramBinary::getLength()
1790{
1791 GLint length;
1792 if (save(NULL, INT_MAX, &length))
1793 {
1794 return length;
1795 }
1796 else
1797 {
1798 return 0;
1799 }
1800}
1801
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001802bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001803{
1804 if (!fragmentShader || !fragmentShader->isCompiled())
1805 {
1806 return false;
1807 }
1808
1809 if (!vertexShader || !vertexShader->isCompiled())
1810 {
1811 return false;
1812 }
1813
1814 std::string pixelHLSL = fragmentShader->getHLSL();
1815 std::string vertexHLSL = vertexShader->getHLSL();
1816
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001817 if (!linkVaryings(infoLog, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001818 {
1819 return false;
1820 }
1821
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001822 bool success = true;
1823 D3DConstantTable *constantTableVS = NULL;
1824 D3DConstantTable *constantTablePS = NULL;
daniel@transgaming.coma9c71422012-11-28 20:58:45 +00001825 rx::ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), GL_VERTEX_SHADER);
1826 rx::ShaderExecutable *pixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), GL_FRAGMENT_SHADER);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001827
daniel@transgaming.coma9c71422012-11-28 20:58:45 +00001828 if (vertexExecutable && pixelExecutable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001829 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001830 mVertexExecutable = rx::ShaderExecutable9::makeShaderExecutable9(vertexExecutable);
1831 mPixelExecutable = rx::ShaderExecutable9::makeShaderExecutable9(pixelExecutable);
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001832
daniel@transgaming.com95892412012-11-28 20:59:09 +00001833 constantTableVS = mVertexExecutable->getConstantTable();
1834 constantTablePS = mPixelExecutable->getConstantTable();
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001835 }
1836 else
1837 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001838 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001839 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001840
1841 delete vertexExecutable;
1842 vertexExecutable = NULL;
1843 delete pixelExecutable;
1844 pixelExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001845 }
1846
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001847 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1848 {
1849 success = false;
1850 }
1851
1852 if (constantTableVS && constantTablePS)
1853 {
1854 if (!linkUniforms(infoLog, constantTableVS, constantTablePS))
1855 {
1856 success = false;
1857 }
1858 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001859
1860 // these uniforms are searched as already-decorated because gl_ and dx_
1861 // are reserved prefixes, and do not receive additional decoration
1862 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
1863 mDxDepthLocation = getUniformLocation("dx_Depth");
1864 mDxCoordLocation = getUniformLocation("dx_Coord");
1865 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
1866 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
1867 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
1868
1869 Context *context = getContext();
1870 context->markDxUniformsDirty();
1871
1872 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001873}
1874
1875// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001876bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001877{
1878 unsigned int usedLocations = 0;
1879
1880 // Link attributes that have a binding location
1881 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1882 {
1883 int location = attributeBindings.getAttributeBinding(attribute->name);
1884
1885 if (location != -1) // Set by glBindAttribLocation
1886 {
1887 if (!mLinkedAttribute[location].name.empty())
1888 {
1889 // Multiple active attributes bound to the same location; not an error
1890 }
1891
1892 mLinkedAttribute[location] = *attribute;
1893
1894 int rows = VariableRowCount(attribute->type);
1895
1896 if (rows + location > MAX_VERTEX_ATTRIBS)
1897 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001898 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 +00001899
1900 return false;
1901 }
1902
1903 for (int i = 0; i < rows; i++)
1904 {
1905 usedLocations |= 1 << (location + i);
1906 }
1907 }
1908 }
1909
1910 // Link attributes that don't have a binding location
1911 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1912 {
1913 int location = attributeBindings.getAttributeBinding(attribute->name);
1914
1915 if (location == -1) // Not set by glBindAttribLocation
1916 {
1917 int rows = VariableRowCount(attribute->type);
1918 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1919
1920 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1921 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001922 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001923
1924 return false; // Fail to link
1925 }
1926
1927 mLinkedAttribute[availableIndex] = *attribute;
1928 }
1929 }
1930
1931 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1932 {
1933 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1934 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1935
1936 for (int r = 0; r < rows; r++)
1937 {
1938 mSemanticIndex[attributeIndex++] = index++;
1939 }
1940 }
1941
1942 return true;
1943}
1944
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001945bool ProgramBinary::linkUniforms(InfoLog &infoLog, D3DConstantTable *vsConstantTable, D3DConstantTable *psConstantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001946{
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001947 for (unsigned int constantIndex = 0; constantIndex < psConstantTable->constants(); constantIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001948 {
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001949 const D3DConstant *constant = psConstantTable->getConstant(constantIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001950
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001951 if (!defineUniform(infoLog, GL_FRAGMENT_SHADER, constant, "", vsConstantTable, psConstantTable))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001952 {
1953 return false;
1954 }
1955 }
1956
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001957 for (unsigned int constantIndex = 0; constantIndex < vsConstantTable->constants(); constantIndex++)
1958 {
1959 const D3DConstant *constant = vsConstantTable->getConstant(constantIndex);
1960
1961 if (!defineUniform(infoLog, GL_VERTEX_SHADER, constant, "", vsConstantTable, psConstantTable))
1962 {
1963 return false;
1964 }
1965 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001966 return true;
1967}
1968
1969// Adds the description of a constant found in the binary shader to the list of uniforms
1970// Returns true if succesful (uniform not already defined)
daniel@transgaming.com59d9ab12012-11-28 20:58:14 +00001971bool ProgramBinary::defineUniform(InfoLog &infoLog, GLenum shader, const D3DConstant *constant, const std::string &name,
1972 D3DConstantTable *vsConstantTable, D3DConstantTable *psConstantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001973{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001974 if (constant->registerSet == D3DConstant::RS_SAMPLER)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001975 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001976 for (unsigned int i = 0; i < constant->registerCount; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001977 {
daniel@transgaming.com59d9ab12012-11-28 20:58:14 +00001978 const D3DConstant *psConstant = psConstantTable->getConstantByName(constant->name.c_str());
1979 const D3DConstant *vsConstant = vsConstantTable->getConstantByName(constant->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001980
1981 if (psConstant)
1982 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001983 unsigned int samplerIndex = psConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001984
1985 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1986 {
1987 mSamplersPS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001988 mSamplersPS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001989 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
1990 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
1991 }
1992 else
1993 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001994 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001995 return false;
1996 }
1997 }
1998
1999 if (vsConstant)
2000 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002001 unsigned int samplerIndex = vsConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002002
2003 if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
2004 {
2005 mSamplersVS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002006 mSamplersVS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002007 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2008 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2009 }
2010 else
2011 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002012 infoLog.append("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002013 return false;
2014 }
2015 }
2016 }
2017 }
2018
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002019 switch(constant->typeClass)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002020 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002021 case D3DConstant::CLASS_STRUCT:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002022 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002023 for (unsigned int arrayIndex = 0; arrayIndex < constant->elements; arrayIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002024 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002025 for (unsigned int field = 0; field < constant->structMembers[arrayIndex].size(); field++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002026 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002027 const D3DConstant *fieldConstant = constant->structMembers[arrayIndex][field];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002028
apatrick@chromium.org85fee292012-09-06 00:43:06 +00002029 std::string structIndex = (constant->elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002030
daniel@transgaming.com59d9ab12012-11-28 20:58:14 +00002031 if (!defineUniform(infoLog, shader, fieldConstant, name + constant->name + structIndex + ".", vsConstantTable, psConstantTable))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002032 {
2033 return false;
2034 }
2035 }
2036 }
2037
2038 return true;
2039 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002040 case D3DConstant::CLASS_SCALAR:
2041 case D3DConstant::CLASS_VECTOR:
2042 case D3DConstant::CLASS_MATRIX_COLUMNS:
2043 case D3DConstant::CLASS_OBJECT:
2044 return defineUniform(shader, constant, name + constant->name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002045 default:
2046 UNREACHABLE();
2047 return false;
2048 }
2049}
2050
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002051bool ProgramBinary::defineUniform(GLenum shader, const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002052{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002053 Uniform *uniform = createUniform(constant, _name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002054
2055 if(!uniform)
2056 {
2057 return false;
2058 }
2059
2060 // Check if already defined
2061 GLint location = getUniformLocation(uniform->name);
2062 GLenum type = uniform->type;
2063
2064 if (location >= 0)
2065 {
2066 delete uniform;
2067 uniform = mUniforms[mUniformIndex[location].index];
2068 }
2069
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002070 if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constant);
2071 if (shader == GL_VERTEX_SHADER) uniform->vs.set(constant);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002072
2073 if (location >= 0)
2074 {
2075 return uniform->type == type;
2076 }
2077
2078 mUniforms.push_back(uniform);
2079 unsigned int uniformIndex = mUniforms.size() - 1;
2080
2081 for (unsigned int i = 0; i < uniform->arraySize; ++i)
2082 {
2083 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
2084 }
2085
2086 return true;
2087}
2088
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002089Uniform *ProgramBinary::createUniform(const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002090{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002091 if (constant->rows == 1) // Vectors and scalars
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002092 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002093 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002094 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002095 case D3DConstant::PT_SAMPLER2D:
2096 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002097 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002098 case 1: return new Uniform(GL_SAMPLER_2D, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002099 default: UNREACHABLE();
2100 }
2101 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002102 case D3DConstant::PT_SAMPLERCUBE:
2103 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002104 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002105 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002106 default: UNREACHABLE();
2107 }
2108 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002109 case D3DConstant::PT_BOOL:
2110 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002111 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002112 case 1: return new Uniform(GL_BOOL, _name, constant->elements);
2113 case 2: return new Uniform(GL_BOOL_VEC2, _name, constant->elements);
2114 case 3: return new Uniform(GL_BOOL_VEC3, _name, constant->elements);
2115 case 4: return new Uniform(GL_BOOL_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002116 default: UNREACHABLE();
2117 }
2118 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002119 case D3DConstant::PT_INT:
2120 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002121 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002122 case 1: return new Uniform(GL_INT, _name, constant->elements);
2123 case 2: return new Uniform(GL_INT_VEC2, _name, constant->elements);
2124 case 3: return new Uniform(GL_INT_VEC3, _name, constant->elements);
2125 case 4: return new Uniform(GL_INT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002126 default: UNREACHABLE();
2127 }
2128 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002129 case D3DConstant::PT_FLOAT:
2130 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002131 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002132 case 1: return new Uniform(GL_FLOAT, _name, constant->elements);
2133 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constant->elements);
2134 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constant->elements);
2135 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002136 default: UNREACHABLE();
2137 }
2138 break;
2139 default:
2140 UNREACHABLE();
2141 }
2142 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002143 else if (constant->rows == constant->columns) // Square matrices
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002144 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002145 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002146 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002147 case D3DConstant::PT_FLOAT:
2148 switch (constant->rows)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002149 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002150 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constant->elements);
2151 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constant->elements);
2152 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002153 default: UNREACHABLE();
2154 }
2155 break;
2156 default: UNREACHABLE();
2157 }
2158 }
2159 else UNREACHABLE();
2160
2161 return 0;
2162}
2163
2164// This method needs to match OutputHLSL::decorate
2165std::string ProgramBinary::decorateAttribute(const std::string &name)
2166{
2167 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2168 {
2169 return "_" + name;
2170 }
2171
2172 return name;
2173}
2174
2175std::string ProgramBinary::undecorateUniform(const std::string &_name)
2176{
2177 std::string name = _name;
2178
2179 // Remove any structure field decoration
2180 size_t pos = 0;
2181 while ((pos = name.find("._", pos)) != std::string::npos)
2182 {
2183 name.replace(pos, 2, ".");
2184 }
2185
2186 // Remove the leading decoration
2187 if (name[0] == '_')
2188 {
2189 return name.substr(1);
2190 }
2191 else if (name.compare(0, 3, "ar_") == 0)
2192 {
2193 return name.substr(3);
2194 }
2195
2196 return name;
2197}
2198
2199void ProgramBinary::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
2200{
2201 float vector[D3D9_MAX_FLOAT_CONSTANTS * 4];
2202 BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS];
2203
2204 if (targetUniform->ps.float4Index >= 0 || targetUniform->vs.float4Index >= 0)
2205 {
2206 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2207 for (int i = 0; i < count; i++)
2208 {
2209 for (int j = 0; j < 4; j++)
2210 {
2211 if (j < width)
2212 {
2213 vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f;
2214 }
2215 else
2216 {
2217 vector[i * 4 + j] = 0.0f;
2218 }
2219 }
2220 }
2221 }
2222
2223 if (targetUniform->ps.boolIndex >= 0 || targetUniform->vs.boolIndex >= 0)
2224 {
2225 int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0;
2226 int vsCount = targetUniform->vs.boolIndex >= 0 ? targetUniform->vs.registerCount : 0;
2227 int copyCount = std::min(count * width, std::max(psCount, vsCount));
2228 ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS);
2229 for (int i = 0; i < copyCount; i++)
2230 {
2231 boolVector[i] = v[i] != GL_FALSE;
2232 }
2233 }
2234
2235 if (targetUniform->ps.float4Index >= 0)
2236 {
2237 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount);
2238 }
2239
2240 if (targetUniform->ps.boolIndex >= 0)
2241 {
2242 mDevice->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount);
2243 }
2244
2245 if (targetUniform->vs.float4Index >= 0)
2246 {
2247 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount);
2248 }
2249
2250 if (targetUniform->vs.boolIndex >= 0)
2251 {
2252 mDevice->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount);
2253 }
2254}
2255
2256bool ProgramBinary::applyUniformnfv(Uniform *targetUniform, const GLfloat *v)
2257{
2258 if (targetUniform->ps.registerCount)
2259 {
2260 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount);
2261 }
2262
2263 if (targetUniform->vs.registerCount)
2264 {
2265 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount);
2266 }
2267
2268 return true;
2269}
2270
2271bool ProgramBinary::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2272{
2273 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002274 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002275
2276 for (int i = 0; i < count; i++)
2277 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002278 vector[i] = Vector4((float)v[i], 0, 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002279 }
2280
2281 if (targetUniform->ps.registerCount)
2282 {
2283 if (targetUniform->ps.samplerIndex >= 0)
2284 {
2285 unsigned int firstIndex = targetUniform->ps.samplerIndex;
2286
2287 for (int i = 0; i < count; i++)
2288 {
2289 unsigned int samplerIndex = firstIndex + i;
2290
2291 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2292 {
2293 ASSERT(mSamplersPS[samplerIndex].active);
2294 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
2295 }
2296 }
2297 }
2298 else
2299 {
2300 ASSERT(targetUniform->ps.float4Index >= 0);
2301 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount);
2302 }
2303 }
2304
2305 if (targetUniform->vs.registerCount)
2306 {
2307 if (targetUniform->vs.samplerIndex >= 0)
2308 {
2309 unsigned int firstIndex = targetUniform->vs.samplerIndex;
2310
2311 for (int i = 0; i < count; i++)
2312 {
2313 unsigned int samplerIndex = firstIndex + i;
2314
2315 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2316 {
2317 ASSERT(mSamplersVS[samplerIndex].active);
2318 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2319 }
2320 }
2321 }
2322 else
2323 {
2324 ASSERT(targetUniform->vs.float4Index >= 0);
2325 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2326 }
2327 }
2328
2329 return true;
2330}
2331
2332bool ProgramBinary::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2333{
2334 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002335 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002336
2337 for (int i = 0; i < count; i++)
2338 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002339 vector[i] = Vector4((float)v[0], (float)v[1], 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002340
2341 v += 2;
2342 }
2343
2344 applyUniformniv(targetUniform, count, vector);
2345
2346 return true;
2347}
2348
2349bool ProgramBinary::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2350{
2351 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002352 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002353
2354 for (int i = 0; i < count; i++)
2355 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002356 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002357
2358 v += 3;
2359 }
2360
2361 applyUniformniv(targetUniform, count, vector);
2362
2363 return true;
2364}
2365
2366bool ProgramBinary::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2367{
2368 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002369 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002370
2371 for (int i = 0; i < count; i++)
2372 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002373 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002374
2375 v += 4;
2376 }
2377
2378 applyUniformniv(targetUniform, count, vector);
2379
2380 return true;
2381}
2382
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002383void ProgramBinary::applyUniformniv(Uniform *targetUniform, GLsizei count, const Vector4 *vector)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002384{
2385 if (targetUniform->ps.registerCount)
2386 {
2387 ASSERT(targetUniform->ps.float4Index >= 0);
2388 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount);
2389 }
2390
2391 if (targetUniform->vs.registerCount)
2392 {
2393 ASSERT(targetUniform->vs.float4Index >= 0);
2394 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2395 }
2396}
2397
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002398bool ProgramBinary::isValidated() const
2399{
2400 return mValidated;
2401}
2402
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002403void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2404{
2405 // Skip over inactive attributes
2406 unsigned int activeAttribute = 0;
2407 unsigned int attribute;
2408 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2409 {
2410 if (mLinkedAttribute[attribute].name.empty())
2411 {
2412 continue;
2413 }
2414
2415 if (activeAttribute == index)
2416 {
2417 break;
2418 }
2419
2420 activeAttribute++;
2421 }
2422
2423 if (bufsize > 0)
2424 {
2425 const char *string = mLinkedAttribute[attribute].name.c_str();
2426
2427 strncpy(name, string, bufsize);
2428 name[bufsize - 1] = '\0';
2429
2430 if (length)
2431 {
2432 *length = strlen(name);
2433 }
2434 }
2435
2436 *size = 1; // Always a single 'type' instance
2437
2438 *type = mLinkedAttribute[attribute].type;
2439}
2440
2441GLint ProgramBinary::getActiveAttributeCount()
2442{
2443 int count = 0;
2444
2445 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2446 {
2447 if (!mLinkedAttribute[attributeIndex].name.empty())
2448 {
2449 count++;
2450 }
2451 }
2452
2453 return count;
2454}
2455
2456GLint ProgramBinary::getActiveAttributeMaxLength()
2457{
2458 int maxLength = 0;
2459
2460 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2461 {
2462 if (!mLinkedAttribute[attributeIndex].name.empty())
2463 {
2464 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2465 }
2466 }
2467
2468 return maxLength;
2469}
2470
2471void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2472{
2473 // Skip over internal uniforms
2474 unsigned int activeUniform = 0;
2475 unsigned int uniform;
2476 for (uniform = 0; uniform < mUniforms.size(); uniform++)
2477 {
2478 if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0)
2479 {
2480 continue;
2481 }
2482
2483 if (activeUniform == index)
2484 {
2485 break;
2486 }
2487
2488 activeUniform++;
2489 }
2490
2491 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2492
2493 if (bufsize > 0)
2494 {
2495 std::string string = mUniforms[uniform]->name;
2496
2497 if (mUniforms[uniform]->isArray())
2498 {
2499 string += "[0]";
2500 }
2501
2502 strncpy(name, string.c_str(), bufsize);
2503 name[bufsize - 1] = '\0';
2504
2505 if (length)
2506 {
2507 *length = strlen(name);
2508 }
2509 }
2510
2511 *size = mUniforms[uniform]->arraySize;
2512
2513 *type = mUniforms[uniform]->type;
2514}
2515
2516GLint ProgramBinary::getActiveUniformCount()
2517{
2518 int count = 0;
2519
2520 unsigned int numUniforms = mUniforms.size();
2521 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2522 {
2523 if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2524 {
2525 count++;
2526 }
2527 }
2528
2529 return count;
2530}
2531
2532GLint ProgramBinary::getActiveUniformMaxLength()
2533{
2534 int maxLength = 0;
2535
2536 unsigned int numUniforms = mUniforms.size();
2537 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2538 {
2539 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2540 {
2541 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2542 if (mUniforms[uniformIndex]->isArray())
2543 {
2544 length += 3; // Counting in "[0]".
2545 }
2546 maxLength = std::max(length, maxLength);
2547 }
2548 }
2549
2550 return maxLength;
2551}
2552
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002553void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002554{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002555 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002556 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002557 {
2558 mValidated = false;
2559 }
2560 else
2561 {
2562 mValidated = true;
2563 }
2564}
2565
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002566bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002567{
2568 // if any two active samplers in a program are of different types, but refer to the same
2569 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2570 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2571
2572 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
2573 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2574
2575 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2576 {
2577 textureUnitType[i] = TEXTURE_UNKNOWN;
2578 }
2579
2580 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2581 {
2582 if (mSamplersPS[i].active)
2583 {
2584 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2585
2586 if (unit >= maxCombinedTextureImageUnits)
2587 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002588 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002589 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002590 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002591 }
2592
2593 return false;
2594 }
2595
2596 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2597 {
2598 if (mSamplersPS[i].textureType != textureUnitType[unit])
2599 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002600 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002601 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002602 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002603 }
2604
2605 return false;
2606 }
2607 }
2608 else
2609 {
2610 textureUnitType[unit] = mSamplersPS[i].textureType;
2611 }
2612 }
2613 }
2614
2615 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2616 {
2617 if (mSamplersVS[i].active)
2618 {
2619 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2620
2621 if (unit >= maxCombinedTextureImageUnits)
2622 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002623 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002624 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002625 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002626 }
2627
2628 return false;
2629 }
2630
2631 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2632 {
2633 if (mSamplersVS[i].textureType != textureUnitType[unit])
2634 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002635 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002636 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002637 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002638 }
2639
2640 return false;
2641 }
2642 }
2643 else
2644 {
2645 textureUnitType[unit] = mSamplersVS[i].textureType;
2646 }
2647 }
2648 }
2649
2650 return true;
2651}
2652
2653GLint ProgramBinary::getDxDepthRangeLocation() const
2654{
2655 return mDxDepthRangeLocation;
2656}
2657
2658GLint ProgramBinary::getDxDepthLocation() const
2659{
2660 return mDxDepthLocation;
2661}
2662
2663GLint ProgramBinary::getDxCoordLocation() const
2664{
2665 return mDxCoordLocation;
2666}
2667
2668GLint ProgramBinary::getDxHalfPixelSizeLocation() const
2669{
2670 return mDxHalfPixelSizeLocation;
2671}
2672
2673GLint ProgramBinary::getDxFrontCCWLocation() const
2674{
2675 return mDxFrontCCWLocation;
2676}
2677
2678GLint ProgramBinary::getDxPointsOrLinesLocation() const
2679{
2680 return mDxPointsOrLinesLocation;
2681}
2682
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002683ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2684{
2685}
2686
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002687}