blob: fe3b58cff1bc33fa34d138dd5daaf2b537886ee2 [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.com4f0f65e2012-11-28 21:00:00 +00001646 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
1647 pixelShaderSize, GL_FRAGMENT_SHADER, NULL);
1648 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001649 {
1650 infoLog.append("Could not create pixel shader.");
1651 return false;
1652 }
1653
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001654 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
1655 vertexShaderSize, GL_VERTEX_SHADER, NULL);
1656 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001657 {
1658 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001659 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001660 mPixelExecutable = NULL;
1661 return false;
1662 }
1663
1664 return true;
1665}
1666
1667bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1668{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001669 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001670
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001671 stream.write(GL_PROGRAM_BINARY_ANGLE);
1672 stream.write(BUILD_REVISION);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001673
1674 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1675 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001676 stream.write(mLinkedAttribute[i].type);
1677 stream.write(mLinkedAttribute[i].name);
1678 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001679 }
1680
1681 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1682 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001683 stream.write(mSamplersPS[i].active);
1684 stream.write(mSamplersPS[i].logicalTextureUnit);
1685 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001686 }
1687
1688 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1689 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001690 stream.write(mSamplersVS[i].active);
1691 stream.write(mSamplersVS[i].logicalTextureUnit);
1692 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001693 }
1694
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001695 stream.write(mUsedVertexSamplerRange);
1696 stream.write(mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001697
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001698 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001699 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1700 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001701 stream.write(mUniforms[i]->type);
1702 stream.write(mUniforms[i]->_name);
1703 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001704
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001705 stream.write(mUniforms[i]->ps.float4Index);
1706 stream.write(mUniforms[i]->ps.samplerIndex);
1707 stream.write(mUniforms[i]->ps.boolIndex);
1708 stream.write(mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001709
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001710 stream.write(mUniforms[i]->vs.float4Index);
1711 stream.write(mUniforms[i]->vs.samplerIndex);
1712 stream.write(mUniforms[i]->vs.boolIndex);
1713 stream.write(mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001714 }
1715
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001716 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001717 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1718 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001719 stream.write(mUniformIndex[i].name);
1720 stream.write(mUniformIndex[i].element);
1721 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001722 }
1723
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001724 stream.write(mDxDepthRangeLocation);
1725 stream.write(mDxDepthLocation);
1726 stream.write(mDxCoordLocation);
1727 stream.write(mDxHalfPixelSizeLocation);
1728 stream.write(mDxFrontCCWLocation);
1729 stream.write(mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001730
1731 UINT pixelShaderSize;
daniel@transgaming.comc0ccbd82012-11-28 20:59:37 +00001732 bool result = mPixelExecutable->getPixelFunction(NULL, &pixelShaderSize);
1733 ASSERT(result);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001734 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001735
1736 UINT vertexShaderSize;
daniel@transgaming.comc0ccbd82012-11-28 20:59:37 +00001737 result = mVertexExecutable->getVertexFunction(NULL, &vertexShaderSize);
1738 ASSERT(result);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001739 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001740
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001741 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001742
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001743 GLsizei streamLength = stream.length();
1744 const void *streamData = stream.data();
1745
1746 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001747 if (totalLength > bufSize)
1748 {
1749 if (length)
1750 {
1751 *length = 0;
1752 }
1753
1754 return false;
1755 }
1756
1757 if (binary)
1758 {
1759 char *ptr = (char*) binary;
1760
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001761 memcpy(ptr, streamData, streamLength);
1762 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001763
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001764 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001765 ptr += sizeof(GUID);
1766
daniel@transgaming.comc0ccbd82012-11-28 20:59:37 +00001767 result = mPixelExecutable->getPixelFunction(ptr, &pixelShaderSize);
1768 ASSERT(result);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001769 ptr += pixelShaderSize;
1770
daniel@transgaming.comc0ccbd82012-11-28 20:59:37 +00001771 result = mVertexExecutable->getVertexFunction(ptr, &vertexShaderSize);
1772 ASSERT(result);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001773 ptr += vertexShaderSize;
1774
1775 ASSERT(ptr - totalLength == binary);
1776 }
1777
1778 if (length)
1779 {
1780 *length = totalLength;
1781 }
1782
1783 return true;
1784}
1785
1786GLint ProgramBinary::getLength()
1787{
1788 GLint length;
1789 if (save(NULL, INT_MAX, &length))
1790 {
1791 return length;
1792 }
1793 else
1794 {
1795 return 0;
1796 }
1797}
1798
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001799bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001800{
1801 if (!fragmentShader || !fragmentShader->isCompiled())
1802 {
1803 return false;
1804 }
1805
1806 if (!vertexShader || !vertexShader->isCompiled())
1807 {
1808 return false;
1809 }
1810
1811 std::string pixelHLSL = fragmentShader->getHLSL();
1812 std::string vertexHLSL = vertexShader->getHLSL();
1813
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001814 if (!linkVaryings(infoLog, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001815 {
1816 return false;
1817 }
1818
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001819 bool success = true;
1820 D3DConstantTable *constantTableVS = NULL;
1821 D3DConstantTable *constantTablePS = NULL;
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001822 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), GL_VERTEX_SHADER);
1823 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), GL_FRAGMENT_SHADER);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001824
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001825 if (mVertexExecutable && mPixelExecutable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001826 {
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001827 // D3D9_REPLACE
daniel@transgaming.com95892412012-11-28 20:59:09 +00001828 constantTableVS = mVertexExecutable->getConstantTable();
1829 constantTablePS = mPixelExecutable->getConstantTable();
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001830 }
1831 else
1832 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001833 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001834 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001835
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001836 delete mVertexExecutable;
1837 mVertexExecutable = NULL;
1838 delete mPixelExecutable;
1839 mPixelExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001840 }
1841
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001842 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1843 {
1844 success = false;
1845 }
1846
1847 if (constantTableVS && constantTablePS)
1848 {
1849 if (!linkUniforms(infoLog, constantTableVS, constantTablePS))
1850 {
1851 success = false;
1852 }
1853 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001854
1855 // these uniforms are searched as already-decorated because gl_ and dx_
1856 // are reserved prefixes, and do not receive additional decoration
1857 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
1858 mDxDepthLocation = getUniformLocation("dx_Depth");
1859 mDxCoordLocation = getUniformLocation("dx_Coord");
1860 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
1861 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
1862 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
1863
1864 Context *context = getContext();
1865 context->markDxUniformsDirty();
1866
1867 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001868}
1869
1870// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001871bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001872{
1873 unsigned int usedLocations = 0;
1874
1875 // Link attributes that have a binding location
1876 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1877 {
1878 int location = attributeBindings.getAttributeBinding(attribute->name);
1879
1880 if (location != -1) // Set by glBindAttribLocation
1881 {
1882 if (!mLinkedAttribute[location].name.empty())
1883 {
1884 // Multiple active attributes bound to the same location; not an error
1885 }
1886
1887 mLinkedAttribute[location] = *attribute;
1888
1889 int rows = VariableRowCount(attribute->type);
1890
1891 if (rows + location > MAX_VERTEX_ATTRIBS)
1892 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001893 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 +00001894
1895 return false;
1896 }
1897
1898 for (int i = 0; i < rows; i++)
1899 {
1900 usedLocations |= 1 << (location + i);
1901 }
1902 }
1903 }
1904
1905 // Link attributes that don't have a binding location
1906 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1907 {
1908 int location = attributeBindings.getAttributeBinding(attribute->name);
1909
1910 if (location == -1) // Not set by glBindAttribLocation
1911 {
1912 int rows = VariableRowCount(attribute->type);
1913 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1914
1915 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1916 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001917 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001918
1919 return false; // Fail to link
1920 }
1921
1922 mLinkedAttribute[availableIndex] = *attribute;
1923 }
1924 }
1925
1926 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1927 {
1928 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1929 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1930
1931 for (int r = 0; r < rows; r++)
1932 {
1933 mSemanticIndex[attributeIndex++] = index++;
1934 }
1935 }
1936
1937 return true;
1938}
1939
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001940bool ProgramBinary::linkUniforms(InfoLog &infoLog, D3DConstantTable *vsConstantTable, D3DConstantTable *psConstantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001941{
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001942 for (unsigned int constantIndex = 0; constantIndex < psConstantTable->constants(); constantIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001943 {
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001944 const D3DConstant *constant = psConstantTable->getConstant(constantIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001945
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001946 if (!defineUniform(infoLog, GL_FRAGMENT_SHADER, constant, "", vsConstantTable, psConstantTable))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001947 {
1948 return false;
1949 }
1950 }
1951
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001952 for (unsigned int constantIndex = 0; constantIndex < vsConstantTable->constants(); constantIndex++)
1953 {
1954 const D3DConstant *constant = vsConstantTable->getConstant(constantIndex);
1955
1956 if (!defineUniform(infoLog, GL_VERTEX_SHADER, constant, "", vsConstantTable, psConstantTable))
1957 {
1958 return false;
1959 }
1960 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001961 return true;
1962}
1963
1964// Adds the description of a constant found in the binary shader to the list of uniforms
1965// Returns true if succesful (uniform not already defined)
daniel@transgaming.com59d9ab12012-11-28 20:58:14 +00001966bool ProgramBinary::defineUniform(InfoLog &infoLog, GLenum shader, const D3DConstant *constant, const std::string &name,
1967 D3DConstantTable *vsConstantTable, D3DConstantTable *psConstantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001968{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001969 if (constant->registerSet == D3DConstant::RS_SAMPLER)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001970 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001971 for (unsigned int i = 0; i < constant->registerCount; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001972 {
daniel@transgaming.com59d9ab12012-11-28 20:58:14 +00001973 const D3DConstant *psConstant = psConstantTable->getConstantByName(constant->name.c_str());
1974 const D3DConstant *vsConstant = vsConstantTable->getConstantByName(constant->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001975
1976 if (psConstant)
1977 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001978 unsigned int samplerIndex = psConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001979
1980 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1981 {
1982 mSamplersPS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001983 mSamplersPS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001984 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
1985 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
1986 }
1987 else
1988 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001989 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001990 return false;
1991 }
1992 }
1993
1994 if (vsConstant)
1995 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001996 unsigned int samplerIndex = vsConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001997
1998 if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
1999 {
2000 mSamplersVS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002001 mSamplersVS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002002 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2003 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2004 }
2005 else
2006 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002007 infoLog.append("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002008 return false;
2009 }
2010 }
2011 }
2012 }
2013
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002014 switch(constant->typeClass)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002015 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002016 case D3DConstant::CLASS_STRUCT:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002017 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002018 for (unsigned int arrayIndex = 0; arrayIndex < constant->elements; arrayIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002019 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002020 for (unsigned int field = 0; field < constant->structMembers[arrayIndex].size(); field++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002021 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002022 const D3DConstant *fieldConstant = constant->structMembers[arrayIndex][field];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002023
apatrick@chromium.org85fee292012-09-06 00:43:06 +00002024 std::string structIndex = (constant->elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002025
daniel@transgaming.com59d9ab12012-11-28 20:58:14 +00002026 if (!defineUniform(infoLog, shader, fieldConstant, name + constant->name + structIndex + ".", vsConstantTable, psConstantTable))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002027 {
2028 return false;
2029 }
2030 }
2031 }
2032
2033 return true;
2034 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002035 case D3DConstant::CLASS_SCALAR:
2036 case D3DConstant::CLASS_VECTOR:
2037 case D3DConstant::CLASS_MATRIX_COLUMNS:
2038 case D3DConstant::CLASS_OBJECT:
2039 return defineUniform(shader, constant, name + constant->name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002040 default:
2041 UNREACHABLE();
2042 return false;
2043 }
2044}
2045
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002046bool ProgramBinary::defineUniform(GLenum shader, const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002047{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002048 Uniform *uniform = createUniform(constant, _name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002049
2050 if(!uniform)
2051 {
2052 return false;
2053 }
2054
2055 // Check if already defined
2056 GLint location = getUniformLocation(uniform->name);
2057 GLenum type = uniform->type;
2058
2059 if (location >= 0)
2060 {
2061 delete uniform;
2062 uniform = mUniforms[mUniformIndex[location].index];
2063 }
2064
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002065 if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constant);
2066 if (shader == GL_VERTEX_SHADER) uniform->vs.set(constant);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002067
2068 if (location >= 0)
2069 {
2070 return uniform->type == type;
2071 }
2072
2073 mUniforms.push_back(uniform);
2074 unsigned int uniformIndex = mUniforms.size() - 1;
2075
2076 for (unsigned int i = 0; i < uniform->arraySize; ++i)
2077 {
2078 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
2079 }
2080
2081 return true;
2082}
2083
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002084Uniform *ProgramBinary::createUniform(const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002085{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002086 if (constant->rows == 1) // Vectors and scalars
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002087 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002088 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002089 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002090 case D3DConstant::PT_SAMPLER2D:
2091 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002092 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002093 case 1: return new Uniform(GL_SAMPLER_2D, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002094 default: UNREACHABLE();
2095 }
2096 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002097 case D3DConstant::PT_SAMPLERCUBE:
2098 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002099 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002100 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002101 default: UNREACHABLE();
2102 }
2103 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002104 case D3DConstant::PT_BOOL:
2105 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002106 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002107 case 1: return new Uniform(GL_BOOL, _name, constant->elements);
2108 case 2: return new Uniform(GL_BOOL_VEC2, _name, constant->elements);
2109 case 3: return new Uniform(GL_BOOL_VEC3, _name, constant->elements);
2110 case 4: return new Uniform(GL_BOOL_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002111 default: UNREACHABLE();
2112 }
2113 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002114 case D3DConstant::PT_INT:
2115 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002116 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002117 case 1: return new Uniform(GL_INT, _name, constant->elements);
2118 case 2: return new Uniform(GL_INT_VEC2, _name, constant->elements);
2119 case 3: return new Uniform(GL_INT_VEC3, _name, constant->elements);
2120 case 4: return new Uniform(GL_INT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002121 default: UNREACHABLE();
2122 }
2123 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002124 case D3DConstant::PT_FLOAT:
2125 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002126 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002127 case 1: return new Uniform(GL_FLOAT, _name, constant->elements);
2128 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constant->elements);
2129 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constant->elements);
2130 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002131 default: UNREACHABLE();
2132 }
2133 break;
2134 default:
2135 UNREACHABLE();
2136 }
2137 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002138 else if (constant->rows == constant->columns) // Square matrices
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002139 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002140 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002141 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002142 case D3DConstant::PT_FLOAT:
2143 switch (constant->rows)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002144 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002145 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constant->elements);
2146 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constant->elements);
2147 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002148 default: UNREACHABLE();
2149 }
2150 break;
2151 default: UNREACHABLE();
2152 }
2153 }
2154 else UNREACHABLE();
2155
2156 return 0;
2157}
2158
2159// This method needs to match OutputHLSL::decorate
2160std::string ProgramBinary::decorateAttribute(const std::string &name)
2161{
2162 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2163 {
2164 return "_" + name;
2165 }
2166
2167 return name;
2168}
2169
2170std::string ProgramBinary::undecorateUniform(const std::string &_name)
2171{
2172 std::string name = _name;
2173
2174 // Remove any structure field decoration
2175 size_t pos = 0;
2176 while ((pos = name.find("._", pos)) != std::string::npos)
2177 {
2178 name.replace(pos, 2, ".");
2179 }
2180
2181 // Remove the leading decoration
2182 if (name[0] == '_')
2183 {
2184 return name.substr(1);
2185 }
2186 else if (name.compare(0, 3, "ar_") == 0)
2187 {
2188 return name.substr(3);
2189 }
2190
2191 return name;
2192}
2193
2194void ProgramBinary::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
2195{
2196 float vector[D3D9_MAX_FLOAT_CONSTANTS * 4];
2197 BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS];
2198
2199 if (targetUniform->ps.float4Index >= 0 || targetUniform->vs.float4Index >= 0)
2200 {
2201 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2202 for (int i = 0; i < count; i++)
2203 {
2204 for (int j = 0; j < 4; j++)
2205 {
2206 if (j < width)
2207 {
2208 vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f;
2209 }
2210 else
2211 {
2212 vector[i * 4 + j] = 0.0f;
2213 }
2214 }
2215 }
2216 }
2217
2218 if (targetUniform->ps.boolIndex >= 0 || targetUniform->vs.boolIndex >= 0)
2219 {
2220 int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0;
2221 int vsCount = targetUniform->vs.boolIndex >= 0 ? targetUniform->vs.registerCount : 0;
2222 int copyCount = std::min(count * width, std::max(psCount, vsCount));
2223 ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS);
2224 for (int i = 0; i < copyCount; i++)
2225 {
2226 boolVector[i] = v[i] != GL_FALSE;
2227 }
2228 }
2229
2230 if (targetUniform->ps.float4Index >= 0)
2231 {
2232 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount);
2233 }
2234
2235 if (targetUniform->ps.boolIndex >= 0)
2236 {
2237 mDevice->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount);
2238 }
2239
2240 if (targetUniform->vs.float4Index >= 0)
2241 {
2242 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount);
2243 }
2244
2245 if (targetUniform->vs.boolIndex >= 0)
2246 {
2247 mDevice->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount);
2248 }
2249}
2250
2251bool ProgramBinary::applyUniformnfv(Uniform *targetUniform, const GLfloat *v)
2252{
2253 if (targetUniform->ps.registerCount)
2254 {
2255 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount);
2256 }
2257
2258 if (targetUniform->vs.registerCount)
2259 {
2260 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount);
2261 }
2262
2263 return true;
2264}
2265
2266bool ProgramBinary::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2267{
2268 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002269 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002270
2271 for (int i = 0; i < count; i++)
2272 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002273 vector[i] = Vector4((float)v[i], 0, 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002274 }
2275
2276 if (targetUniform->ps.registerCount)
2277 {
2278 if (targetUniform->ps.samplerIndex >= 0)
2279 {
2280 unsigned int firstIndex = targetUniform->ps.samplerIndex;
2281
2282 for (int i = 0; i < count; i++)
2283 {
2284 unsigned int samplerIndex = firstIndex + i;
2285
2286 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2287 {
2288 ASSERT(mSamplersPS[samplerIndex].active);
2289 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
2290 }
2291 }
2292 }
2293 else
2294 {
2295 ASSERT(targetUniform->ps.float4Index >= 0);
2296 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount);
2297 }
2298 }
2299
2300 if (targetUniform->vs.registerCount)
2301 {
2302 if (targetUniform->vs.samplerIndex >= 0)
2303 {
2304 unsigned int firstIndex = targetUniform->vs.samplerIndex;
2305
2306 for (int i = 0; i < count; i++)
2307 {
2308 unsigned int samplerIndex = firstIndex + i;
2309
2310 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2311 {
2312 ASSERT(mSamplersVS[samplerIndex].active);
2313 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2314 }
2315 }
2316 }
2317 else
2318 {
2319 ASSERT(targetUniform->vs.float4Index >= 0);
2320 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2321 }
2322 }
2323
2324 return true;
2325}
2326
2327bool ProgramBinary::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2328{
2329 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002330 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002331
2332 for (int i = 0; i < count; i++)
2333 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002334 vector[i] = Vector4((float)v[0], (float)v[1], 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002335
2336 v += 2;
2337 }
2338
2339 applyUniformniv(targetUniform, count, vector);
2340
2341 return true;
2342}
2343
2344bool ProgramBinary::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2345{
2346 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002347 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002348
2349 for (int i = 0; i < count; i++)
2350 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002351 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002352
2353 v += 3;
2354 }
2355
2356 applyUniformniv(targetUniform, count, vector);
2357
2358 return true;
2359}
2360
2361bool ProgramBinary::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2362{
2363 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002364 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002365
2366 for (int i = 0; i < count; i++)
2367 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002368 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002369
2370 v += 4;
2371 }
2372
2373 applyUniformniv(targetUniform, count, vector);
2374
2375 return true;
2376}
2377
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002378void ProgramBinary::applyUniformniv(Uniform *targetUniform, GLsizei count, const Vector4 *vector)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002379{
2380 if (targetUniform->ps.registerCount)
2381 {
2382 ASSERT(targetUniform->ps.float4Index >= 0);
2383 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount);
2384 }
2385
2386 if (targetUniform->vs.registerCount)
2387 {
2388 ASSERT(targetUniform->vs.float4Index >= 0);
2389 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2390 }
2391}
2392
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002393bool ProgramBinary::isValidated() const
2394{
2395 return mValidated;
2396}
2397
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002398void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2399{
2400 // Skip over inactive attributes
2401 unsigned int activeAttribute = 0;
2402 unsigned int attribute;
2403 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2404 {
2405 if (mLinkedAttribute[attribute].name.empty())
2406 {
2407 continue;
2408 }
2409
2410 if (activeAttribute == index)
2411 {
2412 break;
2413 }
2414
2415 activeAttribute++;
2416 }
2417
2418 if (bufsize > 0)
2419 {
2420 const char *string = mLinkedAttribute[attribute].name.c_str();
2421
2422 strncpy(name, string, bufsize);
2423 name[bufsize - 1] = '\0';
2424
2425 if (length)
2426 {
2427 *length = strlen(name);
2428 }
2429 }
2430
2431 *size = 1; // Always a single 'type' instance
2432
2433 *type = mLinkedAttribute[attribute].type;
2434}
2435
2436GLint ProgramBinary::getActiveAttributeCount()
2437{
2438 int count = 0;
2439
2440 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2441 {
2442 if (!mLinkedAttribute[attributeIndex].name.empty())
2443 {
2444 count++;
2445 }
2446 }
2447
2448 return count;
2449}
2450
2451GLint ProgramBinary::getActiveAttributeMaxLength()
2452{
2453 int maxLength = 0;
2454
2455 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2456 {
2457 if (!mLinkedAttribute[attributeIndex].name.empty())
2458 {
2459 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2460 }
2461 }
2462
2463 return maxLength;
2464}
2465
2466void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2467{
2468 // Skip over internal uniforms
2469 unsigned int activeUniform = 0;
2470 unsigned int uniform;
2471 for (uniform = 0; uniform < mUniforms.size(); uniform++)
2472 {
2473 if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0)
2474 {
2475 continue;
2476 }
2477
2478 if (activeUniform == index)
2479 {
2480 break;
2481 }
2482
2483 activeUniform++;
2484 }
2485
2486 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2487
2488 if (bufsize > 0)
2489 {
2490 std::string string = mUniforms[uniform]->name;
2491
2492 if (mUniforms[uniform]->isArray())
2493 {
2494 string += "[0]";
2495 }
2496
2497 strncpy(name, string.c_str(), bufsize);
2498 name[bufsize - 1] = '\0';
2499
2500 if (length)
2501 {
2502 *length = strlen(name);
2503 }
2504 }
2505
2506 *size = mUniforms[uniform]->arraySize;
2507
2508 *type = mUniforms[uniform]->type;
2509}
2510
2511GLint ProgramBinary::getActiveUniformCount()
2512{
2513 int count = 0;
2514
2515 unsigned int numUniforms = mUniforms.size();
2516 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2517 {
2518 if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2519 {
2520 count++;
2521 }
2522 }
2523
2524 return count;
2525}
2526
2527GLint ProgramBinary::getActiveUniformMaxLength()
2528{
2529 int maxLength = 0;
2530
2531 unsigned int numUniforms = mUniforms.size();
2532 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2533 {
2534 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2535 {
2536 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2537 if (mUniforms[uniformIndex]->isArray())
2538 {
2539 length += 3; // Counting in "[0]".
2540 }
2541 maxLength = std::max(length, maxLength);
2542 }
2543 }
2544
2545 return maxLength;
2546}
2547
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002548void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002549{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002550 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002551 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002552 {
2553 mValidated = false;
2554 }
2555 else
2556 {
2557 mValidated = true;
2558 }
2559}
2560
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002561bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002562{
2563 // if any two active samplers in a program are of different types, but refer to the same
2564 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2565 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2566
2567 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
2568 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2569
2570 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2571 {
2572 textureUnitType[i] = TEXTURE_UNKNOWN;
2573 }
2574
2575 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2576 {
2577 if (mSamplersPS[i].active)
2578 {
2579 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2580
2581 if (unit >= maxCombinedTextureImageUnits)
2582 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002583 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002584 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002585 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002586 }
2587
2588 return false;
2589 }
2590
2591 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2592 {
2593 if (mSamplersPS[i].textureType != textureUnitType[unit])
2594 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002595 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002596 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002597 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002598 }
2599
2600 return false;
2601 }
2602 }
2603 else
2604 {
2605 textureUnitType[unit] = mSamplersPS[i].textureType;
2606 }
2607 }
2608 }
2609
2610 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2611 {
2612 if (mSamplersVS[i].active)
2613 {
2614 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2615
2616 if (unit >= maxCombinedTextureImageUnits)
2617 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002618 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002619 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002620 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002621 }
2622
2623 return false;
2624 }
2625
2626 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2627 {
2628 if (mSamplersVS[i].textureType != textureUnitType[unit])
2629 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002630 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002631 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002632 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002633 }
2634
2635 return false;
2636 }
2637 }
2638 else
2639 {
2640 textureUnitType[unit] = mSamplersVS[i].textureType;
2641 }
2642 }
2643 }
2644
2645 return true;
2646}
2647
2648GLint ProgramBinary::getDxDepthRangeLocation() const
2649{
2650 return mDxDepthRangeLocation;
2651}
2652
2653GLint ProgramBinary::getDxDepthLocation() const
2654{
2655 return mDxDepthLocation;
2656}
2657
2658GLint ProgramBinary::getDxCoordLocation() const
2659{
2660 return mDxCoordLocation;
2661}
2662
2663GLint ProgramBinary::getDxHalfPixelSizeLocation() const
2664{
2665 return mDxHalfPixelSizeLocation;
2666}
2667
2668GLint ProgramBinary::getDxFrontCCWLocation() const
2669{
2670 return mDxFrontCCWLocation;
2671}
2672
2673GLint ProgramBinary::getDxPointsOrLinesLocation() const
2674{
2675 return mDxPointsOrLinesLocation;
2676}
2677
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002678ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2679{
2680}
2681
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002682}