blob: fe03997d5d49ade184b36f610fd6d780ec54239b [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.com77fbf972012-11-28 21:02:55 +000060ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000061{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000062 mPixelExecutable = NULL;
63 mVertexExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000064
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000065 mValidated = false;
66
67 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
68 {
69 mSemanticIndex[index] = -1;
70 }
71
72 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
73 {
74 mSamplersPS[index].active = false;
75 }
76
77 for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
78 {
79 mSamplersVS[index].active = false;
80 }
81
82 mUsedVertexSamplerRange = 0;
83 mUsedPixelSamplerRange = 0;
84
85 mDxDepthRangeLocation = -1;
86 mDxDepthLocation = -1;
87 mDxCoordLocation = -1;
88 mDxHalfPixelSizeLocation = -1;
89 mDxFrontCCWLocation = -1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000090}
91
92ProgramBinary::~ProgramBinary()
93{
daniel@transgaming.com95892412012-11-28 20:59:09 +000094 delete mPixelExecutable;
95 delete mVertexExecutable;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000096
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000097 while (!mUniforms.empty())
98 {
99 delete mUniforms.back();
100 mUniforms.pop_back();
101 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000102}
103
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000104unsigned int ProgramBinary::getSerial() const
105{
106 return mSerial;
107}
108
109unsigned int ProgramBinary::issueSerial()
110{
111 return mCurrentSerial++;
112}
113
daniel@transgaming.com95892412012-11-28 20:59:09 +0000114rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000115{
116 return mPixelExecutable;
117}
118
daniel@transgaming.com95892412012-11-28 20:59:09 +0000119rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000120{
121 return mVertexExecutable;
122}
123
124GLuint ProgramBinary::getAttributeLocation(const char *name)
125{
126 if (name)
127 {
128 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
129 {
130 if (mLinkedAttribute[index].name == std::string(name))
131 {
132 return index;
133 }
134 }
135 }
136
137 return -1;
138}
139
140int ProgramBinary::getSemanticIndex(int attributeIndex)
141{
142 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
143
144 return mSemanticIndex[attributeIndex];
145}
146
147// Returns one more than the highest sampler index used.
148GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
149{
150 switch (type)
151 {
152 case SAMPLER_PIXEL:
153 return mUsedPixelSamplerRange;
154 case SAMPLER_VERTEX:
155 return mUsedVertexSamplerRange;
156 default:
157 UNREACHABLE();
158 return 0;
159 }
160}
161
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000162bool ProgramBinary::usesPointSize() const
163{
164 return mUsesPointSize;
165}
166
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000167// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
168// index (0-15 for the pixel shader and 0-3 for the vertex shader).
169GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
170{
171 GLint logicalTextureUnit = -1;
172
173 switch (type)
174 {
175 case SAMPLER_PIXEL:
176 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
177
178 if (mSamplersPS[samplerIndex].active)
179 {
180 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
181 }
182 break;
183 case SAMPLER_VERTEX:
184 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
185
186 if (mSamplersVS[samplerIndex].active)
187 {
188 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
189 }
190 break;
191 default: UNREACHABLE();
192 }
193
194 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)getContext()->getMaximumCombinedTextureImageUnits())
195 {
196 return logicalTextureUnit;
197 }
198
199 return -1;
200}
201
202// Returns the texture type for a given Direct3D 9 sampler type and
203// index (0-15 for the pixel shader and 0-3 for the vertex shader).
204TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
205{
206 switch (type)
207 {
208 case SAMPLER_PIXEL:
209 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
210 ASSERT(mSamplersPS[samplerIndex].active);
211 return mSamplersPS[samplerIndex].textureType;
212 case SAMPLER_VERTEX:
213 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
214 ASSERT(mSamplersVS[samplerIndex].active);
215 return mSamplersVS[samplerIndex].textureType;
216 default: UNREACHABLE();
217 }
218
219 return TEXTURE_2D;
220}
221
222GLint ProgramBinary::getUniformLocation(std::string name)
223{
224 unsigned int subscript = 0;
225
226 // Strip any trailing array operator and retrieve the subscript
227 size_t open = name.find_last_of('[');
228 size_t close = name.find_last_of(']');
229 if (open != std::string::npos && close == name.length() - 1)
230 {
231 subscript = atoi(name.substr(open + 1).c_str());
232 name.erase(open);
233 }
234
235 unsigned int numUniforms = mUniformIndex.size();
236 for (unsigned int location = 0; location < numUniforms; location++)
237 {
238 if (mUniformIndex[location].name == name &&
239 mUniformIndex[location].element == subscript)
240 {
241 return location;
242 }
243 }
244
245 return -1;
246}
247
248bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
249{
250 if (location < 0 || location >= (int)mUniformIndex.size())
251 {
252 return false;
253 }
254
255 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
256 targetUniform->dirty = true;
257
258 if (targetUniform->type == GL_FLOAT)
259 {
260 int arraySize = targetUniform->arraySize;
261
262 if (arraySize == 1 && count > 1)
263 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
264
265 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
266
267 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
268
269 for (int i = 0; i < count; i++)
270 {
271 target[0] = v[0];
272 target[1] = 0;
273 target[2] = 0;
274 target[3] = 0;
275 target += 4;
276 v += 1;
277 }
278 }
279 else if (targetUniform->type == GL_BOOL)
280 {
281 int arraySize = targetUniform->arraySize;
282
283 if (arraySize == 1 && count > 1)
284 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
285
286 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
287 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
288
289 for (int i = 0; i < count; ++i)
290 {
291 if (v[i] == 0.0f)
292 {
293 boolParams[i] = GL_FALSE;
294 }
295 else
296 {
297 boolParams[i] = GL_TRUE;
298 }
299 }
300 }
301 else
302 {
303 return false;
304 }
305
306 return true;
307}
308
309bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
310{
311 if (location < 0 || location >= (int)mUniformIndex.size())
312 {
313 return false;
314 }
315
316 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
317 targetUniform->dirty = true;
318
319 if (targetUniform->type == GL_FLOAT_VEC2)
320 {
321 int arraySize = targetUniform->arraySize;
322
323 if (arraySize == 1 && count > 1)
324 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
325
326 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
327
328 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
329
330 for (int i = 0; i < count; i++)
331 {
332 target[0] = v[0];
333 target[1] = v[1];
334 target[2] = 0;
335 target[3] = 0;
336 target += 4;
337 v += 2;
338 }
339 }
340 else if (targetUniform->type == GL_BOOL_VEC2)
341 {
342 int arraySize = targetUniform->arraySize;
343
344 if (arraySize == 1 && count > 1)
345 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
346
347 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
348
349 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
350
351 for (int i = 0; i < count * 2; ++i)
352 {
353 if (v[i] == 0.0f)
354 {
355 boolParams[i] = GL_FALSE;
356 }
357 else
358 {
359 boolParams[i] = GL_TRUE;
360 }
361 }
362 }
363 else
364 {
365 return false;
366 }
367
368 return true;
369}
370
371bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
372{
373 if (location < 0 || location >= (int)mUniformIndex.size())
374 {
375 return false;
376 }
377
378 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
379 targetUniform->dirty = true;
380
381 if (targetUniform->type == GL_FLOAT_VEC3)
382 {
383 int arraySize = targetUniform->arraySize;
384
385 if (arraySize == 1 && count > 1)
386 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
387
388 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
389
390 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
391
392 for (int i = 0; i < count; i++)
393 {
394 target[0] = v[0];
395 target[1] = v[1];
396 target[2] = v[2];
397 target[3] = 0;
398 target += 4;
399 v += 3;
400 }
401 }
402 else if (targetUniform->type == GL_BOOL_VEC3)
403 {
404 int arraySize = targetUniform->arraySize;
405
406 if (arraySize == 1 && count > 1)
407 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
408
409 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
410 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
411
412 for (int i = 0; i < count * 3; ++i)
413 {
414 if (v[i] == 0.0f)
415 {
416 boolParams[i] = GL_FALSE;
417 }
418 else
419 {
420 boolParams[i] = GL_TRUE;
421 }
422 }
423 }
424 else
425 {
426 return false;
427 }
428
429 return true;
430}
431
432bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
433{
434 if (location < 0 || location >= (int)mUniformIndex.size())
435 {
436 return false;
437 }
438
439 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
440 targetUniform->dirty = true;
441
442 if (targetUniform->type == GL_FLOAT_VEC4)
443 {
444 int arraySize = targetUniform->arraySize;
445
446 if (arraySize == 1 && count > 1)
447 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
448
449 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
450
451 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
452 v, 4 * sizeof(GLfloat) * count);
453 }
454 else if (targetUniform->type == GL_BOOL_VEC4)
455 {
456 int arraySize = targetUniform->arraySize;
457
458 if (arraySize == 1 && count > 1)
459 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
460
461 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
462 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
463
464 for (int i = 0; i < count * 4; ++i)
465 {
466 if (v[i] == 0.0f)
467 {
468 boolParams[i] = GL_FALSE;
469 }
470 else
471 {
472 boolParams[i] = GL_TRUE;
473 }
474 }
475 }
476 else
477 {
478 return false;
479 }
480
481 return true;
482}
483
484template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
485void transposeMatrix(T *target, const GLfloat *value)
486{
487 int copyWidth = std::min(targetWidth, srcWidth);
488 int copyHeight = std::min(targetHeight, srcHeight);
489
490 for (int x = 0; x < copyWidth; x++)
491 {
492 for (int y = 0; y < copyHeight; y++)
493 {
494 target[x * targetWidth + y] = (T)value[y * srcWidth + x];
495 }
496 }
497 // clear unfilled right side
498 for (int y = 0; y < copyHeight; y++)
499 {
500 for (int x = srcWidth; x < targetWidth; x++)
501 {
502 target[y * targetWidth + x] = (T)0;
503 }
504 }
505 // clear unfilled bottom.
506 for (int y = srcHeight; y < targetHeight; y++)
507 {
508 for (int x = 0; x < targetWidth; x++)
509 {
510 target[y * targetWidth + x] = (T)0;
511 }
512 }
513}
514
515bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
516{
517 if (location < 0 || location >= (int)mUniformIndex.size())
518 {
519 return false;
520 }
521
522 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
523 targetUniform->dirty = true;
524
525 if (targetUniform->type != GL_FLOAT_MAT2)
526 {
527 return false;
528 }
529
530 int arraySize = targetUniform->arraySize;
531
532 if (arraySize == 1 && count > 1)
533 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
534
535 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
536
537 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
538 for (int i = 0; i < count; i++)
539 {
540 transposeMatrix<GLfloat,4,2,2,2>(target, value);
541 target += 8;
542 value += 4;
543 }
544
545 return true;
546}
547
548bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
549{
550 if (location < 0 || location >= (int)mUniformIndex.size())
551 {
552 return false;
553 }
554
555 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
556 targetUniform->dirty = true;
557
558 if (targetUniform->type != GL_FLOAT_MAT3)
559 {
560 return false;
561 }
562
563 int arraySize = targetUniform->arraySize;
564
565 if (arraySize == 1 && count > 1)
566 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
567
568 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
569
570 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
571 for (int i = 0; i < count; i++)
572 {
573 transposeMatrix<GLfloat,4,3,3,3>(target, value);
574 target += 12;
575 value += 9;
576 }
577
578 return true;
579}
580
581
582bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
583{
584 if (location < 0 || location >= (int)mUniformIndex.size())
585 {
586 return false;
587 }
588
589 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
590 targetUniform->dirty = true;
591
592 if (targetUniform->type != GL_FLOAT_MAT4)
593 {
594 return false;
595 }
596
597 int arraySize = targetUniform->arraySize;
598
599 if (arraySize == 1 && count > 1)
600 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
601
602 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
603
604 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
605 for (int i = 0; i < count; i++)
606 {
607 transposeMatrix<GLfloat,4,4,4,4>(target, value);
608 target += 16;
609 value += 16;
610 }
611
612 return true;
613}
614
615bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
616{
617 if (location < 0 || location >= (int)mUniformIndex.size())
618 {
619 return false;
620 }
621
622 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
623 targetUniform->dirty = true;
624
625 if (targetUniform->type == GL_INT ||
626 targetUniform->type == GL_SAMPLER_2D ||
627 targetUniform->type == GL_SAMPLER_CUBE)
628 {
629 int arraySize = targetUniform->arraySize;
630
631 if (arraySize == 1 && count > 1)
632 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
633
634 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
635
636 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
637 v, sizeof(GLint) * count);
638 }
639 else if (targetUniform->type == GL_BOOL)
640 {
641 int arraySize = targetUniform->arraySize;
642
643 if (arraySize == 1 && count > 1)
644 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
645
646 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
647 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
648
649 for (int i = 0; i < count; ++i)
650 {
651 if (v[i] == 0)
652 {
653 boolParams[i] = GL_FALSE;
654 }
655 else
656 {
657 boolParams[i] = GL_TRUE;
658 }
659 }
660 }
661 else
662 {
663 return false;
664 }
665
666 return true;
667}
668
669bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
670{
671 if (location < 0 || location >= (int)mUniformIndex.size())
672 {
673 return false;
674 }
675
676 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
677 targetUniform->dirty = true;
678
679 if (targetUniform->type == GL_INT_VEC2)
680 {
681 int arraySize = targetUniform->arraySize;
682
683 if (arraySize == 1 && count > 1)
684 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
685
686 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
687
688 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
689 v, 2 * sizeof(GLint) * count);
690 }
691 else if (targetUniform->type == GL_BOOL_VEC2)
692 {
693 int arraySize = targetUniform->arraySize;
694
695 if (arraySize == 1 && count > 1)
696 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
697
698 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
699 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
700
701 for (int i = 0; i < count * 2; ++i)
702 {
703 if (v[i] == 0)
704 {
705 boolParams[i] = GL_FALSE;
706 }
707 else
708 {
709 boolParams[i] = GL_TRUE;
710 }
711 }
712 }
713 else
714 {
715 return false;
716 }
717
718 return true;
719}
720
721bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
722{
723 if (location < 0 || location >= (int)mUniformIndex.size())
724 {
725 return false;
726 }
727
728 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
729 targetUniform->dirty = true;
730
731 if (targetUniform->type == GL_INT_VEC3)
732 {
733 int arraySize = targetUniform->arraySize;
734
735 if (arraySize == 1 && count > 1)
736 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
737
738 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
739
740 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
741 v, 3 * sizeof(GLint) * count);
742 }
743 else if (targetUniform->type == GL_BOOL_VEC3)
744 {
745 int arraySize = targetUniform->arraySize;
746
747 if (arraySize == 1 && count > 1)
748 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
749
750 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
751 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
752
753 for (int i = 0; i < count * 3; ++i)
754 {
755 if (v[i] == 0)
756 {
757 boolParams[i] = GL_FALSE;
758 }
759 else
760 {
761 boolParams[i] = GL_TRUE;
762 }
763 }
764 }
765 else
766 {
767 return false;
768 }
769
770 return true;
771}
772
773bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
774{
775 if (location < 0 || location >= (int)mUniformIndex.size())
776 {
777 return false;
778 }
779
780 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
781 targetUniform->dirty = true;
782
783 if (targetUniform->type == GL_INT_VEC4)
784 {
785 int arraySize = targetUniform->arraySize;
786
787 if (arraySize == 1 && count > 1)
788 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
789
790 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
791
792 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
793 v, 4 * sizeof(GLint) * count);
794 }
795 else if (targetUniform->type == GL_BOOL_VEC4)
796 {
797 int arraySize = targetUniform->arraySize;
798
799 if (arraySize == 1 && count > 1)
800 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
801
802 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
803 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
804
805 for (int i = 0; i < count * 4; ++i)
806 {
807 if (v[i] == 0)
808 {
809 boolParams[i] = GL_FALSE;
810 }
811 else
812 {
813 boolParams[i] = GL_TRUE;
814 }
815 }
816 }
817 else
818 {
819 return false;
820 }
821
822 return true;
823}
824
825bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
826{
827 if (location < 0 || location >= (int)mUniformIndex.size())
828 {
829 return false;
830 }
831
832 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
833
834 // sized queries -- ensure the provided buffer is large enough
835 if (bufSize)
836 {
837 int requiredBytes = UniformExternalSize(targetUniform->type);
838 if (*bufSize < requiredBytes)
839 {
840 return false;
841 }
842 }
843
844 switch (targetUniform->type)
845 {
846 case GL_FLOAT_MAT2:
847 transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
848 break;
849 case GL_FLOAT_MAT3:
850 transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
851 break;
852 case GL_FLOAT_MAT4:
853 transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
854 break;
855 default:
856 {
857 unsigned int count = UniformExternalComponentCount(targetUniform->type);
858 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
859
860 switch (UniformComponentType(targetUniform->type))
861 {
862 case GL_BOOL:
863 {
864 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * internalCount;
865
866 for (unsigned int i = 0; i < count; ++i)
867 {
868 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
869 }
870 }
871 break;
872 case GL_FLOAT:
873 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLfloat),
874 count * sizeof(GLfloat));
875 break;
876 case GL_INT:
877 {
878 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * internalCount;
879
880 for (unsigned int i = 0; i < count; ++i)
881 {
882 params[i] = (float)intParams[i];
883 }
884 }
885 break;
886 default: UNREACHABLE();
887 }
888 }
889 }
890
891 return true;
892}
893
894bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
895{
896 if (location < 0 || location >= (int)mUniformIndex.size())
897 {
898 return false;
899 }
900
901 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
902
903 // sized queries -- ensure the provided buffer is large enough
904 if (bufSize)
905 {
906 int requiredBytes = UniformExternalSize(targetUniform->type);
907 if (*bufSize < requiredBytes)
908 {
909 return false;
910 }
911 }
912
913 switch (targetUniform->type)
914 {
915 case GL_FLOAT_MAT2:
916 {
917 transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
918 }
919 break;
920 case GL_FLOAT_MAT3:
921 {
922 transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
923 }
924 break;
925 case GL_FLOAT_MAT4:
926 {
927 transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
928 }
929 break;
930 default:
931 {
932 unsigned int count = UniformExternalComponentCount(targetUniform->type);
933 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
934
935 switch (UniformComponentType(targetUniform->type))
936 {
937 case GL_BOOL:
938 {
939 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * internalCount;
940
941 for (unsigned int i = 0; i < count; ++i)
942 {
943 params[i] = (GLint)boolParams[i];
944 }
945 }
946 break;
947 case GL_FLOAT:
948 {
949 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * internalCount;
950
951 for (unsigned int i = 0; i < count; ++i)
952 {
953 params[i] = (GLint)floatParams[i];
954 }
955 }
956 break;
957 case GL_INT:
958 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLint),
959 count * sizeof(GLint));
960 break;
961 default: UNREACHABLE();
962 }
963 }
964 }
965
966 return true;
967}
968
969void ProgramBinary::dirtyAllUniforms()
970{
971 unsigned int numUniforms = mUniforms.size();
972 for (unsigned int index = 0; index < numUniforms; index++)
973 {
974 mUniforms[index]->dirty = true;
975 }
976}
977
978// Applies all the uniforms set for this program object to the Direct3D 9 device
979void ProgramBinary::applyUniforms()
980{
daniel@transgaming.com77fbf972012-11-28 21:02:55 +0000981 if (dynamic_cast<rx::Renderer9*>(mRenderer) == NULL) // D3D9_REPLACE
982 {
983 return; // UNIMPLEMENTED
984 }
985
986 IDirect3DDevice9 *device = rx::Renderer9::makeRenderer9(mRenderer)->getDevice(); // D3D9_REPLACE
987
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000988 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) {
989 Uniform *targetUniform = *ub;
990
991 if (targetUniform->dirty)
992 {
993 int arraySize = targetUniform->arraySize;
994 GLfloat *f = (GLfloat*)targetUniform->data;
995 GLint *i = (GLint*)targetUniform->data;
996 GLboolean *b = (GLboolean*)targetUniform->data;
997
998 switch (targetUniform->type)
999 {
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00001000 case GL_BOOL: applyUniformnbv(device, targetUniform, arraySize, 1, b); break;
1001 case GL_BOOL_VEC2: applyUniformnbv(device, targetUniform, arraySize, 2, b); break;
1002 case GL_BOOL_VEC3: applyUniformnbv(device, targetUniform, arraySize, 3, b); break;
1003 case GL_BOOL_VEC4: applyUniformnbv(device, targetUniform, arraySize, 4, b); break;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001004 case GL_FLOAT:
1005 case GL_FLOAT_VEC2:
1006 case GL_FLOAT_VEC3:
1007 case GL_FLOAT_VEC4:
1008 case GL_FLOAT_MAT2:
1009 case GL_FLOAT_MAT3:
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00001010 case GL_FLOAT_MAT4: applyUniformnfv(device, targetUniform, f); break;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001011 case GL_SAMPLER_2D:
1012 case GL_SAMPLER_CUBE:
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00001013 case GL_INT: applyUniform1iv(device, targetUniform, arraySize, i); break;
1014 case GL_INT_VEC2: applyUniform2iv(device, targetUniform, arraySize, i); break;
1015 case GL_INT_VEC3: applyUniform3iv(device, targetUniform, arraySize, i); break;
1016 case GL_INT_VEC4: applyUniform4iv(device, targetUniform, arraySize, i); break;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001017 default:
1018 UNREACHABLE();
1019 }
1020
1021 targetUniform->dirty = false;
1022 }
1023 }
1024}
1025
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001026// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1027// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001028int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001029{
1030 Context *context = getContext();
1031 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1032
1033 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1034 {
1035 int n = VariableRowCount(varying->type) * varying->size;
1036 int m = VariableColumnCount(varying->type);
1037 bool success = false;
1038
1039 if (m == 2 || m == 3 || m == 4)
1040 {
1041 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
1042 {
1043 bool available = true;
1044
1045 for (int y = 0; y < n && available; y++)
1046 {
1047 for (int x = 0; x < m && available; x++)
1048 {
1049 if (packing[r + y][x])
1050 {
1051 available = false;
1052 }
1053 }
1054 }
1055
1056 if (available)
1057 {
1058 varying->reg = r;
1059 varying->col = 0;
1060
1061 for (int y = 0; y < n; y++)
1062 {
1063 for (int x = 0; x < m; x++)
1064 {
1065 packing[r + y][x] = &*varying;
1066 }
1067 }
1068
1069 success = true;
1070 }
1071 }
1072
1073 if (!success && m == 2)
1074 {
1075 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
1076 {
1077 bool available = true;
1078
1079 for (int y = 0; y < n && available; y++)
1080 {
1081 for (int x = 2; x < 4 && available; x++)
1082 {
1083 if (packing[r + y][x])
1084 {
1085 available = false;
1086 }
1087 }
1088 }
1089
1090 if (available)
1091 {
1092 varying->reg = r;
1093 varying->col = 2;
1094
1095 for (int y = 0; y < n; y++)
1096 {
1097 for (int x = 2; x < 4; x++)
1098 {
1099 packing[r + y][x] = &*varying;
1100 }
1101 }
1102
1103 success = true;
1104 }
1105 }
1106 }
1107 }
1108 else if (m == 1)
1109 {
1110 int space[4] = {0};
1111
1112 for (int y = 0; y < maxVaryingVectors; y++)
1113 {
1114 for (int x = 0; x < 4; x++)
1115 {
1116 space[x] += packing[y][x] ? 0 : 1;
1117 }
1118 }
1119
1120 int column = 0;
1121
1122 for (int x = 0; x < 4; x++)
1123 {
1124 if (space[x] >= n && space[x] < space[column])
1125 {
1126 column = x;
1127 }
1128 }
1129
1130 if (space[column] >= n)
1131 {
1132 for (int r = 0; r < maxVaryingVectors; r++)
1133 {
1134 if (!packing[r][column])
1135 {
1136 varying->reg = r;
1137
1138 for (int y = r; y < r + n; y++)
1139 {
1140 packing[y][column] = &*varying;
1141 }
1142
1143 break;
1144 }
1145 }
1146
1147 varying->col = column;
1148
1149 success = true;
1150 }
1151 }
1152 else UNREACHABLE();
1153
1154 if (!success)
1155 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001156 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001157
1158 return -1;
1159 }
1160 }
1161
1162 // Return the number of used registers
1163 int registers = 0;
1164
1165 for (int r = 0; r < maxVaryingVectors; r++)
1166 {
1167 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1168 {
1169 registers++;
1170 }
1171 }
1172
1173 return registers;
1174}
1175
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001176bool ProgramBinary::linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001177{
1178 if (pixelHLSL.empty() || vertexHLSL.empty())
1179 {
1180 return false;
1181 }
1182
1183 // Reset the varying register assignments
1184 for (VaryingList::iterator fragVar = fragmentShader->mVaryings.begin(); fragVar != fragmentShader->mVaryings.end(); fragVar++)
1185 {
1186 fragVar->reg = -1;
1187 fragVar->col = -1;
1188 }
1189
1190 for (VaryingList::iterator vtxVar = vertexShader->mVaryings.begin(); vtxVar != vertexShader->mVaryings.end(); vtxVar++)
1191 {
1192 vtxVar->reg = -1;
1193 vtxVar->col = -1;
1194 }
1195
1196 // Map the varyings to the register file
1197 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001198 int registers = packVaryings(infoLog, packing, fragmentShader);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001199
1200 if (registers < 0)
1201 {
1202 return false;
1203 }
1204
1205 // Write the HLSL input/output declarations
daniel@transgaming.comc5693152012-11-28 21:03:02 +00001206 const bool sm3 = (mRenderer->getMajorShaderModel() >= 3);
1207 const bool sm4 = (mRenderer->getMajorShaderModel() >= 4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001208 Context *context = getContext();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001209 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1210
1211 if (registers == maxVaryingVectors && fragmentShader->mUsesFragCoord)
1212 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001213 infoLog.append("No varying registers left to support gl_FragCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001214
1215 return false;
1216 }
1217
1218 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1219 {
1220 bool matched = false;
1221
1222 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1223 {
1224 if (output->name == input->name)
1225 {
1226 if (output->type != input->type || output->size != input->size)
1227 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001228 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 +00001229
1230 return false;
1231 }
1232
1233 output->reg = input->reg;
1234 output->col = input->col;
1235
1236 matched = true;
1237 break;
1238 }
1239 }
1240
1241 if (!matched)
1242 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001243 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001244
1245 return false;
1246 }
1247 }
1248
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001249 mUsesPointSize = vertexShader->mUsesPointSize;
1250 std::string varyingSemantic = (mUsesPointSize && sm3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comc5693152012-11-28 21:03:02 +00001251 std::string targetSemantic = sm4 ? "SV_Target" : "COLOR";
daniel@transgaming.com617048e2012-11-28 21:05:22 +00001252 std::string positionSemantic = sm4 ? "SV_POSITION" : "POSITION";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001253
1254 vertexHLSL += "struct VS_INPUT\n"
1255 "{\n";
1256
1257 int semanticIndex = 0;
1258 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1259 {
1260 switch (attribute->type)
1261 {
1262 case GL_FLOAT: vertexHLSL += " float "; break;
1263 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1264 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1265 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1266 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1267 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1268 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1269 default: UNREACHABLE();
1270 }
1271
1272 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1273
1274 semanticIndex += VariableRowCount(attribute->type);
1275 }
1276
1277 vertexHLSL += "};\n"
1278 "\n"
1279 "struct VS_OUTPUT\n"
1280 "{\n"
daniel@transgaming.com617048e2012-11-28 21:05:22 +00001281 " float4 gl_Position : " + positionSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001282
1283 for (int r = 0; r < registers; r++)
1284 {
1285 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1286
1287 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1288 }
1289
1290 if (fragmentShader->mUsesFragCoord)
1291 {
1292 vertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1293 }
1294
1295 if (vertexShader->mUsesPointSize && sm3)
1296 {
1297 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1298 }
1299
1300 vertexHLSL += "};\n"
1301 "\n"
1302 "VS_OUTPUT main(VS_INPUT input)\n"
1303 "{\n";
1304
1305 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1306 {
1307 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1308
1309 if (VariableRowCount(attribute->type) > 1) // Matrix
1310 {
1311 vertexHLSL += "transpose";
1312 }
1313
1314 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1315 }
1316
1317 vertexHLSL += "\n"
1318 " gl_main();\n"
1319 "\n"
1320 " VS_OUTPUT output;\n"
1321 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001322 " output.gl_Position.y = -(gl_Position.y + dx_HalfPixelSize.y * gl_Position.w);\n"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001323 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1324 " output.gl_Position.w = gl_Position.w;\n";
1325
1326 if (vertexShader->mUsesPointSize && sm3)
1327 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001328 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001329 }
1330
1331 if (fragmentShader->mUsesFragCoord)
1332 {
1333 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1334 }
1335
1336 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1337 {
1338 if (varying->reg >= 0)
1339 {
1340 for (int i = 0; i < varying->size; i++)
1341 {
1342 int rows = VariableRowCount(varying->type);
1343
1344 for (int j = 0; j < rows; j++)
1345 {
1346 int r = varying->reg + i * rows + j;
1347 vertexHLSL += " output.v" + str(r);
1348
1349 bool sharedRegister = false; // Register used by multiple varyings
1350
1351 for (int x = 0; x < 4; x++)
1352 {
1353 if (packing[r][x] && packing[r][x] != packing[r][0])
1354 {
1355 sharedRegister = true;
1356 break;
1357 }
1358 }
1359
1360 if(sharedRegister)
1361 {
1362 vertexHLSL += ".";
1363
1364 for (int x = 0; x < 4; x++)
1365 {
1366 if (packing[r][x] == &*varying)
1367 {
1368 switch(x)
1369 {
1370 case 0: vertexHLSL += "x"; break;
1371 case 1: vertexHLSL += "y"; break;
1372 case 2: vertexHLSL += "z"; break;
1373 case 3: vertexHLSL += "w"; break;
1374 }
1375 }
1376 }
1377 }
1378
1379 vertexHLSL += " = " + varying->name;
1380
1381 if (varying->array)
1382 {
1383 vertexHLSL += "[" + str(i) + "]";
1384 }
1385
1386 if (rows > 1)
1387 {
1388 vertexHLSL += "[" + str(j) + "]";
1389 }
1390
1391 vertexHLSL += ";\n";
1392 }
1393 }
1394 }
1395 }
1396
1397 vertexHLSL += "\n"
1398 " return output;\n"
1399 "}\n";
1400
1401 pixelHLSL += "struct PS_INPUT\n"
1402 "{\n";
1403
1404 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1405 {
1406 if (varying->reg >= 0)
1407 {
1408 for (int i = 0; i < varying->size; i++)
1409 {
1410 int rows = VariableRowCount(varying->type);
1411 for (int j = 0; j < rows; j++)
1412 {
1413 std::string n = str(varying->reg + i * rows + j);
1414 pixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
1415 }
1416 }
1417 }
1418 else UNREACHABLE();
1419 }
1420
1421 if (fragmentShader->mUsesFragCoord)
1422 {
1423 pixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1424 if (sm3) {
1425 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1426 }
1427 }
1428
1429 if (fragmentShader->mUsesPointCoord && sm3)
1430 {
1431 pixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1432 }
1433
1434 if (fragmentShader->mUsesFrontFacing)
1435 {
1436 pixelHLSL += " float vFace : VFACE;\n";
1437 }
1438
1439 pixelHLSL += "};\n"
1440 "\n"
1441 "struct PS_OUTPUT\n"
1442 "{\n"
daniel@transgaming.comc5693152012-11-28 21:03:02 +00001443 " float4 gl_Color[1] : " + targetSemantic + ";\n"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001444 "};\n"
1445 "\n"
1446 "PS_OUTPUT main(PS_INPUT input)\n"
1447 "{\n";
1448
1449 if (fragmentShader->mUsesFragCoord)
1450 {
1451 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1452
1453 if (sm3)
1454 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001455 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001456 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001457 }
1458 else
1459 {
1460 // dx_Coord contains the viewport width/2, height/2, center.x and center.y. See Context::applyRenderTarget()
1461 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Coord.x + dx_Coord.z;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001462 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Coord.y + dx_Coord.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001463 }
1464
1465 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
1466 " gl_FragCoord.w = rhw;\n";
1467 }
1468
1469 if (fragmentShader->mUsesPointCoord && sm3)
1470 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001471 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1472 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001473 }
1474
1475 if (fragmentShader->mUsesFrontFacing)
1476 {
daniel@transgaming.com73868582012-12-20 20:56:10 +00001477 pixelHLSL += " gl_FrontFacing = (input.vFace * dx_FrontCCW >= 0.0);\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001478 }
1479
1480 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1481 {
1482 if (varying->reg >= 0)
1483 {
1484 for (int i = 0; i < varying->size; i++)
1485 {
1486 int rows = VariableRowCount(varying->type);
1487 for (int j = 0; j < rows; j++)
1488 {
1489 std::string n = str(varying->reg + i * rows + j);
1490 pixelHLSL += " " + varying->name;
1491
1492 if (varying->array)
1493 {
1494 pixelHLSL += "[" + str(i) + "]";
1495 }
1496
1497 if (rows > 1)
1498 {
1499 pixelHLSL += "[" + str(j) + "]";
1500 }
1501
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001502 switch (VariableColumnCount(varying->type))
1503 {
1504 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1505 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1506 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1507 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1508 default: UNREACHABLE();
1509 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001510 }
1511 }
1512 }
1513 else UNREACHABLE();
1514 }
1515
1516 pixelHLSL += "\n"
1517 " gl_main();\n"
1518 "\n"
1519 " PS_OUTPUT output;\n"
1520 " output.gl_Color[0] = gl_Color[0];\n"
1521 "\n"
1522 " return output;\n"
1523 "}\n";
1524
1525 return true;
1526}
1527
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001528bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1529{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001530 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001531
1532 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001533 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001534 if (format != GL_PROGRAM_BINARY_ANGLE)
1535 {
1536 infoLog.append("Invalid program binary format.");
1537 return false;
1538 }
1539
1540 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001541 stream.read(&version);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001542 if (version != BUILD_REVISION)
1543 {
1544 infoLog.append("Invalid program binary version.");
1545 return false;
1546 }
1547
1548 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1549 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001550 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001551 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001552 stream.read(&name);
1553 mLinkedAttribute[i].name = name;
1554 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001555 }
1556
1557 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1558 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001559 stream.read(&mSamplersPS[i].active);
1560 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001561
1562 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001563 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001564 mSamplersPS[i].textureType = (TextureType) textureType;
1565 }
1566
1567 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1568 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001569 stream.read(&mSamplersVS[i].active);
1570 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001571
1572 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001573 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001574 mSamplersVS[i].textureType = (TextureType) textureType;
1575 }
1576
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001577 stream.read(&mUsedVertexSamplerRange);
1578 stream.read(&mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001579
1580 unsigned int size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001581 stream.read(&size);
1582 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001583 {
1584 infoLog.append("Invalid program binary.");
1585 return false;
1586 }
1587
1588 mUniforms.resize(size);
1589 for (unsigned int i = 0; i < size; ++i)
1590 {
1591 GLenum type;
1592 std::string _name;
1593 unsigned int arraySize;
1594
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001595 stream.read(&type);
1596 stream.read(&_name);
1597 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001598
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001599 mUniforms[i] = new Uniform(type, _name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001600
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001601 stream.read(&mUniforms[i]->ps.float4Index);
1602 stream.read(&mUniforms[i]->ps.samplerIndex);
1603 stream.read(&mUniforms[i]->ps.boolIndex);
1604 stream.read(&mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001605
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001606 stream.read(&mUniforms[i]->vs.float4Index);
1607 stream.read(&mUniforms[i]->vs.samplerIndex);
1608 stream.read(&mUniforms[i]->vs.boolIndex);
1609 stream.read(&mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001610 }
1611
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001612 stream.read(&size);
1613 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001614 {
1615 infoLog.append("Invalid program binary.");
1616 return false;
1617 }
1618
1619 mUniformIndex.resize(size);
1620 for (unsigned int i = 0; i < size; ++i)
1621 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001622 stream.read(&mUniformIndex[i].name);
1623 stream.read(&mUniformIndex[i].element);
1624 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001625 }
1626
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001627 stream.read(&mDxDepthRangeLocation);
1628 stream.read(&mDxDepthLocation);
1629 stream.read(&mDxCoordLocation);
1630 stream.read(&mDxHalfPixelSizeLocation);
1631 stream.read(&mDxFrontCCWLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001632
1633 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001634 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001635
1636 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001637 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001638
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001639 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001640
daniel@transgaming.com36038542012-11-28 20:59:26 +00001641 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001642 ptr += sizeof(GUID);
1643
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001644 GUID identifier = mRenderer->getAdapterIdentifier();
1645 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001646 {
1647 infoLog.append("Invalid program binary.");
1648 return false;
1649 }
1650
1651 const char *pixelShaderFunction = ptr;
1652 ptr += pixelShaderSize;
1653
1654 const char *vertexShaderFunction = ptr;
1655 ptr += vertexShaderSize;
1656
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001657 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
1658 pixelShaderSize, GL_FRAGMENT_SHADER, NULL);
1659 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001660 {
1661 infoLog.append("Could not create pixel shader.");
1662 return false;
1663 }
1664
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001665 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
1666 vertexShaderSize, GL_VERTEX_SHADER, NULL);
1667 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001668 {
1669 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001670 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001671 mPixelExecutable = NULL;
1672 return false;
1673 }
1674
1675 return true;
1676}
1677
1678bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1679{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001680 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001681
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001682 stream.write(GL_PROGRAM_BINARY_ANGLE);
1683 stream.write(BUILD_REVISION);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001684
1685 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1686 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001687 stream.write(mLinkedAttribute[i].type);
1688 stream.write(mLinkedAttribute[i].name);
1689 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001690 }
1691
1692 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1693 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001694 stream.write(mSamplersPS[i].active);
1695 stream.write(mSamplersPS[i].logicalTextureUnit);
1696 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001697 }
1698
1699 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1700 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001701 stream.write(mSamplersVS[i].active);
1702 stream.write(mSamplersVS[i].logicalTextureUnit);
1703 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001704 }
1705
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001706 stream.write(mUsedVertexSamplerRange);
1707 stream.write(mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001708
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001709 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001710 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1711 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001712 stream.write(mUniforms[i]->type);
1713 stream.write(mUniforms[i]->_name);
1714 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001715
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001716 stream.write(mUniforms[i]->ps.float4Index);
1717 stream.write(mUniforms[i]->ps.samplerIndex);
1718 stream.write(mUniforms[i]->ps.boolIndex);
1719 stream.write(mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001720
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001721 stream.write(mUniforms[i]->vs.float4Index);
1722 stream.write(mUniforms[i]->vs.samplerIndex);
1723 stream.write(mUniforms[i]->vs.boolIndex);
1724 stream.write(mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001725 }
1726
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001727 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001728 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1729 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001730 stream.write(mUniformIndex[i].name);
1731 stream.write(mUniformIndex[i].element);
1732 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001733 }
1734
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001735 stream.write(mDxDepthRangeLocation);
1736 stream.write(mDxDepthLocation);
1737 stream.write(mDxCoordLocation);
1738 stream.write(mDxHalfPixelSizeLocation);
1739 stream.write(mDxFrontCCWLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001740
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001741 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001742 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001743
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001744 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001745 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001746
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001747 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001748
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001749 GLsizei streamLength = stream.length();
1750 const void *streamData = stream.data();
1751
1752 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001753 if (totalLength > bufSize)
1754 {
1755 if (length)
1756 {
1757 *length = 0;
1758 }
1759
1760 return false;
1761 }
1762
1763 if (binary)
1764 {
1765 char *ptr = (char*) binary;
1766
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001767 memcpy(ptr, streamData, streamLength);
1768 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001769
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001770 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001771 ptr += sizeof(GUID);
1772
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001773 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001774 ptr += pixelShaderSize;
1775
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001776 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001777 ptr += vertexShaderSize;
1778
1779 ASSERT(ptr - totalLength == binary);
1780 }
1781
1782 if (length)
1783 {
1784 *length = totalLength;
1785 }
1786
1787 return true;
1788}
1789
1790GLint ProgramBinary::getLength()
1791{
1792 GLint length;
1793 if (save(NULL, INT_MAX, &length))
1794 {
1795 return length;
1796 }
1797 else
1798 {
1799 return 0;
1800 }
1801}
1802
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001803bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001804{
1805 if (!fragmentShader || !fragmentShader->isCompiled())
1806 {
1807 return false;
1808 }
1809
1810 if (!vertexShader || !vertexShader->isCompiled())
1811 {
1812 return false;
1813 }
1814
1815 std::string pixelHLSL = fragmentShader->getHLSL();
1816 std::string vertexHLSL = vertexShader->getHLSL();
1817
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001818 if (!linkVaryings(infoLog, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001819 {
1820 return false;
1821 }
1822
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001823 bool success = true;
daniel@transgaming.com31240482012-11-28 21:06:41 +00001824 rx::D3DConstantTable *constantTableVS = NULL;
1825 rx::D3DConstantTable *constantTablePS = NULL;
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001826 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), GL_VERTEX_SHADER);
1827 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), GL_FRAGMENT_SHADER);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001828
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001829 if (mVertexExecutable && mPixelExecutable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001830 {
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001831 // D3D9_REPLACE
daniel@transgaming.com95892412012-11-28 20:59:09 +00001832 constantTableVS = mVertexExecutable->getConstantTable();
1833 constantTablePS = mPixelExecutable->getConstantTable();
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001834 }
1835 else
1836 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001837 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001838 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001839
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001840 delete mVertexExecutable;
1841 mVertexExecutable = NULL;
1842 delete mPixelExecutable;
1843 mPixelExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001844 }
1845
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001846 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1847 {
1848 success = false;
1849 }
1850
1851 if (constantTableVS && constantTablePS)
1852 {
1853 if (!linkUniforms(infoLog, constantTableVS, constantTablePS))
1854 {
1855 success = false;
1856 }
1857 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001858
1859 // these uniforms are searched as already-decorated because gl_ and dx_
1860 // are reserved prefixes, and do not receive additional decoration
1861 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
1862 mDxDepthLocation = getUniformLocation("dx_Depth");
1863 mDxCoordLocation = getUniformLocation("dx_Coord");
1864 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
1865 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001866
1867 Context *context = getContext();
1868 context->markDxUniformsDirty();
1869
1870 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001871}
1872
1873// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001874bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001875{
1876 unsigned int usedLocations = 0;
1877
1878 // Link attributes that have a binding location
1879 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1880 {
1881 int location = attributeBindings.getAttributeBinding(attribute->name);
1882
1883 if (location != -1) // Set by glBindAttribLocation
1884 {
1885 if (!mLinkedAttribute[location].name.empty())
1886 {
1887 // Multiple active attributes bound to the same location; not an error
1888 }
1889
1890 mLinkedAttribute[location] = *attribute;
1891
1892 int rows = VariableRowCount(attribute->type);
1893
1894 if (rows + location > MAX_VERTEX_ATTRIBS)
1895 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001896 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 +00001897
1898 return false;
1899 }
1900
1901 for (int i = 0; i < rows; i++)
1902 {
1903 usedLocations |= 1 << (location + i);
1904 }
1905 }
1906 }
1907
1908 // Link attributes that don't have a binding location
1909 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1910 {
1911 int location = attributeBindings.getAttributeBinding(attribute->name);
1912
1913 if (location == -1) // Not set by glBindAttribLocation
1914 {
1915 int rows = VariableRowCount(attribute->type);
1916 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1917
1918 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1919 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001920 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001921
1922 return false; // Fail to link
1923 }
1924
1925 mLinkedAttribute[availableIndex] = *attribute;
1926 }
1927 }
1928
1929 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1930 {
1931 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1932 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1933
1934 for (int r = 0; r < rows; r++)
1935 {
1936 mSemanticIndex[attributeIndex++] = index++;
1937 }
1938 }
1939
1940 return true;
1941}
1942
daniel@transgaming.com31240482012-11-28 21:06:41 +00001943bool ProgramBinary::linkUniforms(InfoLog &infoLog, rx::D3DConstantTable *vsConstantTable, rx::D3DConstantTable *psConstantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001944{
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001945 for (unsigned int constantIndex = 0; constantIndex < psConstantTable->constants(); constantIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001946 {
daniel@transgaming.com31240482012-11-28 21:06:41 +00001947 const rx::D3DConstant *constant = psConstantTable->getConstant(constantIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001948
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001949 if (!defineUniform(infoLog, GL_FRAGMENT_SHADER, constant, "", vsConstantTable, psConstantTable))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001950 {
1951 return false;
1952 }
1953 }
1954
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001955 for (unsigned int constantIndex = 0; constantIndex < vsConstantTable->constants(); constantIndex++)
1956 {
daniel@transgaming.com31240482012-11-28 21:06:41 +00001957 const rx::D3DConstant *constant = vsConstantTable->getConstant(constantIndex);
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001958
1959 if (!defineUniform(infoLog, GL_VERTEX_SHADER, constant, "", vsConstantTable, psConstantTable))
1960 {
1961 return false;
1962 }
1963 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001964 return true;
1965}
1966
1967// Adds the description of a constant found in the binary shader to the list of uniforms
1968// Returns true if succesful (uniform not already defined)
daniel@transgaming.com31240482012-11-28 21:06:41 +00001969bool ProgramBinary::defineUniform(InfoLog &infoLog, GLenum shader, const rx::D3DConstant *constant, const std::string &name,
1970 rx::D3DConstantTable *vsConstantTable, rx::D3DConstantTable *psConstantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001971{
daniel@transgaming.com31240482012-11-28 21:06:41 +00001972 if (constant->registerSet == rx::D3DConstant::RS_SAMPLER)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001973 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001974 for (unsigned int i = 0; i < constant->registerCount; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001975 {
daniel@transgaming.com31240482012-11-28 21:06:41 +00001976 const rx::D3DConstant *psConstant = psConstantTable->getConstantByName(constant->name.c_str());
1977 const rx::D3DConstant *vsConstant = vsConstantTable->getConstantByName(constant->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001978
1979 if (psConstant)
1980 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001981 unsigned int samplerIndex = psConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001982
1983 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1984 {
1985 mSamplersPS[samplerIndex].active = true;
daniel@transgaming.com31240482012-11-28 21:06:41 +00001986 mSamplersPS[samplerIndex].textureType = (constant->type == rx::D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001987 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
1988 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
1989 }
1990 else
1991 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001992 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001993 return false;
1994 }
1995 }
1996
1997 if (vsConstant)
1998 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001999 unsigned int samplerIndex = vsConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002000
2001 if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
2002 {
2003 mSamplersVS[samplerIndex].active = true;
daniel@transgaming.com31240482012-11-28 21:06:41 +00002004 mSamplersVS[samplerIndex].textureType = (constant->type == rx::D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002005 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2006 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2007 }
2008 else
2009 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002010 infoLog.append("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002011 return false;
2012 }
2013 }
2014 }
2015 }
2016
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002017 switch(constant->typeClass)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002018 {
daniel@transgaming.com31240482012-11-28 21:06:41 +00002019 case rx::D3DConstant::CLASS_STRUCT:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002020 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002021 for (unsigned int arrayIndex = 0; arrayIndex < constant->elements; arrayIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002022 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002023 for (unsigned int field = 0; field < constant->structMembers[arrayIndex].size(); field++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002024 {
daniel@transgaming.com31240482012-11-28 21:06:41 +00002025 const rx::D3DConstant *fieldConstant = constant->structMembers[arrayIndex][field];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002026
apatrick@chromium.org85fee292012-09-06 00:43:06 +00002027 std::string structIndex = (constant->elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002028
daniel@transgaming.com59d9ab12012-11-28 20:58:14 +00002029 if (!defineUniform(infoLog, shader, fieldConstant, name + constant->name + structIndex + ".", vsConstantTable, psConstantTable))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002030 {
2031 return false;
2032 }
2033 }
2034 }
2035
2036 return true;
2037 }
daniel@transgaming.com31240482012-11-28 21:06:41 +00002038 case rx::D3DConstant::CLASS_SCALAR:
2039 case rx::D3DConstant::CLASS_VECTOR:
2040 case rx::D3DConstant::CLASS_MATRIX_COLUMNS:
2041 case rx::D3DConstant::CLASS_OBJECT:
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002042 return defineUniform(shader, constant, name + constant->name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002043 default:
2044 UNREACHABLE();
2045 return false;
2046 }
2047}
2048
daniel@transgaming.com31240482012-11-28 21:06:41 +00002049bool ProgramBinary::defineUniform(GLenum shader, const rx::D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002050{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002051 Uniform *uniform = createUniform(constant, _name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002052
2053 if(!uniform)
2054 {
2055 return false;
2056 }
2057
2058 // Check if already defined
2059 GLint location = getUniformLocation(uniform->name);
2060 GLenum type = uniform->type;
2061
2062 if (location >= 0)
2063 {
2064 delete uniform;
2065 uniform = mUniforms[mUniformIndex[location].index];
2066 }
2067
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002068 if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constant);
2069 if (shader == GL_VERTEX_SHADER) uniform->vs.set(constant);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002070
2071 if (location >= 0)
2072 {
2073 return uniform->type == type;
2074 }
2075
2076 mUniforms.push_back(uniform);
2077 unsigned int uniformIndex = mUniforms.size() - 1;
2078
2079 for (unsigned int i = 0; i < uniform->arraySize; ++i)
2080 {
2081 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
2082 }
2083
2084 return true;
2085}
2086
daniel@transgaming.com31240482012-11-28 21:06:41 +00002087Uniform *ProgramBinary::createUniform(const rx::D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002088{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002089 if (constant->rows == 1) // Vectors and scalars
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002090 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002091 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002092 {
daniel@transgaming.com31240482012-11-28 21:06:41 +00002093 case rx::D3DConstant::PT_SAMPLER2D:
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002094 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002095 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002096 case 1: return new Uniform(GL_SAMPLER_2D, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002097 default: UNREACHABLE();
2098 }
2099 break;
daniel@transgaming.com31240482012-11-28 21:06:41 +00002100 case rx::D3DConstant::PT_SAMPLERCUBE:
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002101 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002102 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002103 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002104 default: UNREACHABLE();
2105 }
2106 break;
daniel@transgaming.com31240482012-11-28 21:06:41 +00002107 case rx::D3DConstant::PT_BOOL:
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002108 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002109 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002110 case 1: return new Uniform(GL_BOOL, _name, constant->elements);
2111 case 2: return new Uniform(GL_BOOL_VEC2, _name, constant->elements);
2112 case 3: return new Uniform(GL_BOOL_VEC3, _name, constant->elements);
2113 case 4: return new Uniform(GL_BOOL_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002114 default: UNREACHABLE();
2115 }
2116 break;
daniel@transgaming.com31240482012-11-28 21:06:41 +00002117 case rx::D3DConstant::PT_INT:
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002118 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002119 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002120 case 1: return new Uniform(GL_INT, _name, constant->elements);
2121 case 2: return new Uniform(GL_INT_VEC2, _name, constant->elements);
2122 case 3: return new Uniform(GL_INT_VEC3, _name, constant->elements);
2123 case 4: return new Uniform(GL_INT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002124 default: UNREACHABLE();
2125 }
2126 break;
daniel@transgaming.com31240482012-11-28 21:06:41 +00002127 case rx::D3DConstant::PT_FLOAT:
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002128 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002129 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002130 case 1: return new Uniform(GL_FLOAT, _name, constant->elements);
2131 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constant->elements);
2132 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constant->elements);
2133 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002134 default: UNREACHABLE();
2135 }
2136 break;
2137 default:
2138 UNREACHABLE();
2139 }
2140 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002141 else if (constant->rows == constant->columns) // Square matrices
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002142 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002143 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002144 {
daniel@transgaming.com31240482012-11-28 21:06:41 +00002145 case rx::D3DConstant::PT_FLOAT:
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002146 switch (constant->rows)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002147 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002148 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constant->elements);
2149 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constant->elements);
2150 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002151 default: UNREACHABLE();
2152 }
2153 break;
2154 default: UNREACHABLE();
2155 }
2156 }
2157 else UNREACHABLE();
2158
2159 return 0;
2160}
2161
2162// This method needs to match OutputHLSL::decorate
2163std::string ProgramBinary::decorateAttribute(const std::string &name)
2164{
2165 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2166 {
2167 return "_" + name;
2168 }
2169
2170 return name;
2171}
2172
2173std::string ProgramBinary::undecorateUniform(const std::string &_name)
2174{
2175 std::string name = _name;
2176
2177 // Remove any structure field decoration
2178 size_t pos = 0;
2179 while ((pos = name.find("._", pos)) != std::string::npos)
2180 {
2181 name.replace(pos, 2, ".");
2182 }
2183
2184 // Remove the leading decoration
2185 if (name[0] == '_')
2186 {
2187 return name.substr(1);
2188 }
2189 else if (name.compare(0, 3, "ar_") == 0)
2190 {
2191 return name.substr(3);
2192 }
2193
2194 return name;
2195}
2196
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002197// D3D9_REPLACE begin
2198void ProgramBinary::applyUniformnbv(IDirect3DDevice9 *device, Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002199{
2200 float vector[D3D9_MAX_FLOAT_CONSTANTS * 4];
2201 BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS];
2202
2203 if (targetUniform->ps.float4Index >= 0 || targetUniform->vs.float4Index >= 0)
2204 {
2205 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2206 for (int i = 0; i < count; i++)
2207 {
2208 for (int j = 0; j < 4; j++)
2209 {
2210 if (j < width)
2211 {
2212 vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f;
2213 }
2214 else
2215 {
2216 vector[i * 4 + j] = 0.0f;
2217 }
2218 }
2219 }
2220 }
2221
2222 if (targetUniform->ps.boolIndex >= 0 || targetUniform->vs.boolIndex >= 0)
2223 {
2224 int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0;
2225 int vsCount = targetUniform->vs.boolIndex >= 0 ? targetUniform->vs.registerCount : 0;
2226 int copyCount = std::min(count * width, std::max(psCount, vsCount));
2227 ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS);
2228 for (int i = 0; i < copyCount; i++)
2229 {
2230 boolVector[i] = v[i] != GL_FALSE;
2231 }
2232 }
2233
2234 if (targetUniform->ps.float4Index >= 0)
2235 {
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002236 device->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002237 }
2238
2239 if (targetUniform->ps.boolIndex >= 0)
2240 {
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002241 device->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002242 }
2243
2244 if (targetUniform->vs.float4Index >= 0)
2245 {
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002246 device->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002247 }
2248
2249 if (targetUniform->vs.boolIndex >= 0)
2250 {
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002251 device->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002252 }
2253}
2254
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002255bool ProgramBinary::applyUniformnfv(IDirect3DDevice9 *device, Uniform *targetUniform, const GLfloat *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002256{
2257 if (targetUniform->ps.registerCount)
2258 {
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002259 device->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002260 }
2261
2262 if (targetUniform->vs.registerCount)
2263 {
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002264 device->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002265 }
2266
2267 return true;
2268}
2269
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002270bool ProgramBinary::applyUniform1iv(IDirect3DDevice9 *device, Uniform *targetUniform, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002271{
2272 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002273 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002274
2275 for (int i = 0; i < count; i++)
2276 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002277 vector[i] = Vector4((float)v[i], 0, 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002278 }
2279
2280 if (targetUniform->ps.registerCount)
2281 {
2282 if (targetUniform->ps.samplerIndex >= 0)
2283 {
2284 unsigned int firstIndex = targetUniform->ps.samplerIndex;
2285
2286 for (int i = 0; i < count; i++)
2287 {
2288 unsigned int samplerIndex = firstIndex + i;
2289
2290 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2291 {
2292 ASSERT(mSamplersPS[samplerIndex].active);
2293 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
2294 }
2295 }
2296 }
2297 else
2298 {
2299 ASSERT(targetUniform->ps.float4Index >= 0);
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002300 device->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002301 }
2302 }
2303
2304 if (targetUniform->vs.registerCount)
2305 {
2306 if (targetUniform->vs.samplerIndex >= 0)
2307 {
2308 unsigned int firstIndex = targetUniform->vs.samplerIndex;
2309
2310 for (int i = 0; i < count; i++)
2311 {
2312 unsigned int samplerIndex = firstIndex + i;
2313
2314 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2315 {
2316 ASSERT(mSamplersVS[samplerIndex].active);
2317 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2318 }
2319 }
2320 }
2321 else
2322 {
2323 ASSERT(targetUniform->vs.float4Index >= 0);
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002324 device->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002325 }
2326 }
2327
2328 return true;
2329}
2330
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002331bool ProgramBinary::applyUniform2iv(IDirect3DDevice9 *device, Uniform *targetUniform, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002332{
2333 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002334 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002335
2336 for (int i = 0; i < count; i++)
2337 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002338 vector[i] = Vector4((float)v[0], (float)v[1], 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002339
2340 v += 2;
2341 }
2342
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002343 applyUniformniv(device, targetUniform, count, vector);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002344
2345 return true;
2346}
2347
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002348bool ProgramBinary::applyUniform3iv(IDirect3DDevice9 *device, Uniform *targetUniform, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002349{
2350 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002351 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002352
2353 for (int i = 0; i < count; i++)
2354 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002355 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002356
2357 v += 3;
2358 }
2359
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002360 applyUniformniv(device, targetUniform, count, vector);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002361
2362 return true;
2363}
2364
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002365bool ProgramBinary::applyUniform4iv(IDirect3DDevice9 *device, Uniform *targetUniform, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002366{
2367 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002368 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002369
2370 for (int i = 0; i < count; i++)
2371 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002372 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002373
2374 v += 4;
2375 }
2376
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002377 applyUniformniv(device, targetUniform, count, vector);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002378
2379 return true;
2380}
2381
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002382void ProgramBinary::applyUniformniv(IDirect3DDevice9 *device, Uniform *targetUniform, GLsizei count, const Vector4 *vector)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002383{
2384 if (targetUniform->ps.registerCount)
2385 {
2386 ASSERT(targetUniform->ps.float4Index >= 0);
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002387 device->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002388 }
2389
2390 if (targetUniform->vs.registerCount)
2391 {
2392 ASSERT(targetUniform->vs.float4Index >= 0);
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002393 device->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002394 }
2395}
daniel@transgaming.com77fbf972012-11-28 21:02:55 +00002396// D3D9_REPLACE end
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002397
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
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}