blob: 5abf345dd0b0fa88b5053b0a30a40ab8719890e1 [file] [log] [blame]
Nicolas Capens0bac2852016-05-07 06:09:58 -04001// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Program.cpp: Implements the Program class. Implements GL program objects
16// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
17
18#include "Program.h"
19
20#include "main.h"
21#include "Buffer.h"
22#include "Shader.h"
23#include "TransformFeedback.h"
24#include "utilities.h"
25#include "common/debug.h"
26#include "Shader/PixelShader.hpp"
27#include "Shader/VertexShader.hpp"
28
Nicolas Capensb28c6622017-01-05 14:37:22 -050029#include <algorithm>
Nicolas Capens0bac2852016-05-07 06:09:58 -040030#include <string>
31#include <stdlib.h>
32
33namespace es2
34{
35 unsigned int Program::currentSerial = 1;
36
37 std::string str(int i)
38 {
39 char buffer[20];
40 sprintf(buffer, "%d", i);
41 return buffer;
42 }
43
44 Uniform::BlockInfo::BlockInfo(const glsl::Uniform& uniform, int blockIndex)
45 {
Nicolas Capens0bac2852016-05-07 06:09:58 -040046 if(blockIndex >= 0)
47 {
48 index = blockIndex;
49 offset = uniform.blockInfo.offset;
50 arrayStride = uniform.blockInfo.arrayStride;
51 matrixStride = uniform.blockInfo.matrixStride;
52 isRowMajorMatrix = uniform.blockInfo.isRowMajorMatrix;
53 }
54 else
55 {
56 index = -1;
57 offset = -1;
58 arrayStride = -1;
59 matrixStride = -1;
60 isRowMajorMatrix = false;
61 }
62 }
63
64 Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize,
65 const BlockInfo &blockInfo)
66 : type(type), precision(precision), name(name), arraySize(arraySize), blockInfo(blockInfo)
67 {
68 if(blockInfo.index == -1)
69 {
70 size_t bytes = UniformTypeSize(type) * size();
71 data = new unsigned char[bytes];
72 memset(data, 0, bytes);
73 }
74 else
75 {
76 data = nullptr;
77 }
78 dirty = true;
79
80 psRegisterIndex = -1;
81 vsRegisterIndex = -1;
82 }
83
84 Uniform::~Uniform()
85 {
86 delete[] data;
87 }
88
89 bool Uniform::isArray() const
90 {
91 return arraySize >= 1;
92 }
93
94 int Uniform::size() const
95 {
96 return arraySize > 0 ? arraySize : 1;
97 }
98
99 int Uniform::registerCount() const
100 {
101 return size() * VariableRegisterCount(type);
102 }
103
104 UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize, std::vector<unsigned int> memberUniformIndexes) :
105 name(name), elementIndex(elementIndex), dataSize(dataSize), memberUniformIndexes(memberUniformIndexes), psRegisterIndex(GL_INVALID_INDEX), vsRegisterIndex(GL_INVALID_INDEX)
106 {
107 }
108
109 void UniformBlock::setRegisterIndex(GLenum shader, unsigned int registerIndex)
110 {
111 switch(shader)
112 {
113 case GL_VERTEX_SHADER:
114 vsRegisterIndex = registerIndex;
115 break;
116 case GL_FRAGMENT_SHADER:
117 psRegisterIndex = registerIndex;
118 break;
119 default:
120 UNREACHABLE(shader);
121 }
122 }
123
124 bool UniformBlock::isArrayElement() const
125 {
126 return elementIndex != GL_INVALID_INDEX;
127 }
128
129 bool UniformBlock::isReferencedByVertexShader() const
130 {
131 return vsRegisterIndex != GL_INVALID_INDEX;
132 }
133
134 bool UniformBlock::isReferencedByFragmentShader() const
135 {
136 return psRegisterIndex != GL_INVALID_INDEX;
137 }
138
139 UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index) : name(name), element(element), index(index)
140 {
141 }
142
143 LinkedVarying::LinkedVarying()
144 {
145 }
146
147 LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, int reg, int col)
148 : name(name), type(type), size(size), reg(reg), col(col)
149 {
150 }
151
152 Program::Program(ResourceManager *manager, GLuint handle) : serial(issueSerial()), resourceManager(manager), handle(handle)
153 {
Nicolas Capens0bac2852016-05-07 06:09:58 -0400154 fragmentShader = 0;
155 vertexShader = 0;
156 pixelBinary = 0;
157 vertexBinary = 0;
158
159 transformFeedbackBufferMode = GL_INTERLEAVED_ATTRIBS;
160 totalLinkedVaryingsComponents = 0;
161
162 infoLog = 0;
163 validated = false;
164
165 resetUniformBlockBindings();
166 unlink();
167
168 orphaned = false;
169 retrievableBinary = false;
170 referenceCount = 0;
171 }
172
173 Program::~Program()
174 {
175 unlink();
176
177 if(vertexShader)
178 {
179 vertexShader->release();
180 }
181
182 if(fragmentShader)
183 {
184 fragmentShader->release();
185 }
186 }
187
188 bool Program::attachShader(Shader *shader)
189 {
190 if(shader->getType() == GL_VERTEX_SHADER)
191 {
192 if(vertexShader)
193 {
194 return false;
195 }
196
197 vertexShader = (VertexShader*)shader;
198 vertexShader->addRef();
199 }
200 else if(shader->getType() == GL_FRAGMENT_SHADER)
201 {
202 if(fragmentShader)
203 {
204 return false;
205 }
206
207 fragmentShader = (FragmentShader*)shader;
208 fragmentShader->addRef();
209 }
210 else UNREACHABLE(shader->getType());
211
212 return true;
213 }
214
215 bool Program::detachShader(Shader *shader)
216 {
217 if(shader->getType() == GL_VERTEX_SHADER)
218 {
219 if(vertexShader != shader)
220 {
221 return false;
222 }
223
224 vertexShader->release();
225 vertexShader = 0;
226 }
227 else if(shader->getType() == GL_FRAGMENT_SHADER)
228 {
229 if(fragmentShader != shader)
230 {
231 return false;
232 }
233
234 fragmentShader->release();
235 fragmentShader = 0;
236 }
237 else UNREACHABLE(shader->getType());
238
239 return true;
240 }
241
242 int Program::getAttachedShadersCount() const
243 {
244 return (vertexShader ? 1 : 0) + (fragmentShader ? 1 : 0);
245 }
246
247 sw::PixelShader *Program::getPixelShader()
248 {
249 return pixelBinary;
250 }
251
252 sw::VertexShader *Program::getVertexShader()
253 {
254 return vertexBinary;
255 }
256
Alexis Hetub3f5ed72017-08-16 16:37:19 -0400257 GLint Program::getFragDataLocation(const GLchar *name)
258 {
259 if(name && linked)
260 {
261 std::string baseName(name);
262 unsigned int subscript = GL_INVALID_INDEX;
263 baseName = ParseUniformName(baseName, &subscript);
Alexis Hetu23f54d72017-12-05 16:03:51 -0500264 for(auto const &input : fragmentShader->varyings)
Alexis Hetub3f5ed72017-08-16 16:37:19 -0400265 {
Alexis Hetu23f54d72017-12-05 16:03:51 -0500266 if(input.name == baseName)
Alexis Hetub3f5ed72017-08-16 16:37:19 -0400267 {
Alexis Hetu23f54d72017-12-05 16:03:51 -0500268 int rowCount = VariableRowCount(input.type);
269 int colCount = VariableColumnCount(input.type);
270 return (subscript == GL_INVALID_INDEX) ? input.reg : input.reg + (rowCount > 1 ? colCount * subscript : subscript);
Alexis Hetub3f5ed72017-08-16 16:37:19 -0400271 }
272 }
273 }
274
275 return -1;
276 }
277
Nicolas Capens0bac2852016-05-07 06:09:58 -0400278 void Program::bindAttributeLocation(GLuint index, const char *name)
279 {
Alexis Hetu23f54d72017-12-05 16:03:51 -0500280 attributeBinding[name] = index;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400281 }
282
Alexis Hetu05c32b92016-06-23 11:32:07 -0400283 GLint Program::getAttributeLocation(const char *name)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400284 {
285 if(name)
286 {
Alexis Hetu23f54d72017-12-05 16:03:51 -0500287 std::string strName(name);
288 for(auto const &it : linkedAttribute)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400289 {
Alexis Hetu23f54d72017-12-05 16:03:51 -0500290 if(it.name == strName)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400291 {
Alexis Hetu23f54d72017-12-05 16:03:51 -0500292 return getAttributeBinding(it);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400293 }
294 }
295 }
296
297 return -1;
298 }
299
300 int Program::getAttributeStream(int attributeIndex)
301 {
302 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
303
304 return attributeStream[attributeIndex];
305 }
306
Alexis Hétu2cd00092018-01-03 13:04:09 +0000307 // Returns the index of the texture image unit (0-19) corresponding to a sampler index (0-15 for the pixel shader and 0-3 for the vertex shader)
308 GLint Program::getSamplerMapping(sw::SamplerType type, unsigned int samplerIndex)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400309 {
Alexis Hétu2cd00092018-01-03 13:04:09 +0000310 GLint logicalTextureUnit = -1;
311
312 switch(type)
313 {
314 case sw::SAMPLER_PIXEL:
315 ASSERT(samplerIndex < sizeof(samplersPS) / sizeof(samplersPS[0]));
316
317 if(samplersPS[samplerIndex].active)
318 {
319 logicalTextureUnit = samplersPS[samplerIndex].logicalTextureUnit;
320 }
321 break;
322 case sw::SAMPLER_VERTEX:
323 ASSERT(samplerIndex < sizeof(samplersVS) / sizeof(samplersVS[0]));
324
325 if(samplersVS[samplerIndex].active)
326 {
327 logicalTextureUnit = samplersVS[samplerIndex].logicalTextureUnit;
328 }
329 break;
330 default: UNREACHABLE(type);
331 }
332
333 if(logicalTextureUnit < MAX_COMBINED_TEXTURE_IMAGE_UNITS)
334 {
335 return logicalTextureUnit;
336 }
337
338 return -1;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400339 }
340
341 // Returns the texture type for a given sampler type and index (0-15 for the pixel shader and 0-3 for the vertex shader)
342 TextureType Program::getSamplerTextureType(sw::SamplerType type, unsigned int samplerIndex)
343 {
344 switch(type)
345 {
346 case sw::SAMPLER_PIXEL:
Alexis Hétu2cd00092018-01-03 13:04:09 +0000347 ASSERT(samplerIndex < sizeof(samplersPS)/sizeof(samplersPS[0]));
348 ASSERT(samplersPS[samplerIndex].active);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400349 return samplersPS[samplerIndex].textureType;
350 case sw::SAMPLER_VERTEX:
Alexis Hétu2cd00092018-01-03 13:04:09 +0000351 ASSERT(samplerIndex < sizeof(samplersVS)/sizeof(samplersVS[0]));
352 ASSERT(samplersVS[samplerIndex].active);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400353 return samplersVS[samplerIndex].textureType;
354 default: UNREACHABLE(type);
355 }
356
357 return TEXTURE_2D;
358 }
359
Alexis Hetuec5da192017-10-06 13:23:49 -0400360 bool Program::isUniformDefined(const std::string &name) const
361 {
362 unsigned int subscript = GL_INVALID_INDEX;
363 std::string baseName = es2::ParseUniformName(name, &subscript);
364
365 size_t numUniforms = uniformIndex.size();
366 for(size_t location = 0; location < numUniforms; location++)
367 {
368 const unsigned int index = uniformIndex[location].index;
369 if((uniformIndex[location].name == baseName) && ((index == GL_INVALID_INDEX) ||
370 ((uniforms[index]->isArray() && uniformIndex[location].element == subscript) ||
371 (subscript == GL_INVALID_INDEX))))
372 {
373 return true;
374 }
375 }
376
377 return false;
378 }
379
Nicolas Capens0bac2852016-05-07 06:09:58 -0400380 GLint Program::getUniformLocation(const std::string &name) const
381 {
Alexis Hetu53977f12016-06-27 16:04:31 -0400382 unsigned int subscript = GL_INVALID_INDEX;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400383 std::string baseName = es2::ParseUniformName(name, &subscript);
384
385 size_t numUniforms = uniformIndex.size();
386 for(size_t location = 0; location < numUniforms; location++)
387 {
Alexis Hetuec5da192017-10-06 13:23:49 -0400388 const unsigned int index = uniformIndex[location].index;
389 if((index != GL_INVALID_INDEX) && (uniformIndex[location].name == baseName) &&
390 ((uniforms[index]->isArray() && uniformIndex[location].element == subscript) ||
Nicolas Capens0bac2852016-05-07 06:09:58 -0400391 (subscript == GL_INVALID_INDEX)))
392 {
393 return (GLint)location;
394 }
395 }
396
397 return -1;
398 }
399
400 GLuint Program::getUniformIndex(const std::string &name) const
401 {
Alexis Hetu53977f12016-06-27 16:04:31 -0400402 unsigned int subscript = GL_INVALID_INDEX;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400403 std::string baseName = es2::ParseUniformName(name, &subscript);
404
405 // The app is not allowed to specify array indices other than 0 for arrays of basic types
406 if(subscript != 0 && subscript != GL_INVALID_INDEX)
407 {
408 return GL_INVALID_INDEX;
409 }
410
411 size_t numUniforms = uniforms.size();
412 for(GLuint index = 0; index < numUniforms; index++)
413 {
414 if(uniforms[index]->name == baseName)
415 {
416 if(uniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
417 {
418 return index;
419 }
420 }
421 }
422
423 return GL_INVALID_INDEX;
424 }
425
426 void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
427 {
428 ASSERT(uniformBlockIndex < getActiveUniformBlockCount());
429
430 const UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];
431
432 switch(pname)
433 {
434 case GL_UNIFORM_BLOCK_DATA_SIZE:
435 *params = static_cast<GLint>(uniformBlock.dataSize);
436 break;
437 case GL_UNIFORM_BLOCK_NAME_LENGTH:
438 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
439 break;
440 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
441 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
442 break;
443 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
444 {
445 for(unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
446 {
447 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
448 }
449 }
450 break;
451 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
452 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
453 break;
454 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
455 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
456 break;
457 default: UNREACHABLE(pname);
458 }
459 }
460
461 GLuint Program::getUniformBlockIndex(const std::string &name) const
462 {
Alexis Hetu53977f12016-06-27 16:04:31 -0400463 unsigned int subscript = GL_INVALID_INDEX;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400464 std::string baseName = es2::ParseUniformName(name, &subscript);
465
466 size_t numUniformBlocks = getActiveUniformBlockCount();
467 for(GLuint blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
468 {
469 const UniformBlock &uniformBlock = *uniformBlocks[blockIndex];
470 if(uniformBlock.name == baseName)
471 {
472 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
473 if(subscript == uniformBlock.elementIndex || arrayElementZero)
474 {
475 return blockIndex;
476 }
477 }
478 }
479
480 return GL_INVALID_INDEX;
481 }
482
483 void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
484 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -0500485 if(uniformBlockIndex >= getActiveUniformBlockCount())
486 {
487 return error(GL_INVALID_VALUE);
488 }
489
Nicolas Capens0bac2852016-05-07 06:09:58 -0400490 uniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
491 }
492
493 GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
494 {
Alexis Hetu48280a42017-11-30 15:04:39 -0500495 if(uniformBlockIndex >= getActiveUniformBlockCount())
496 {
497 return error(GL_INVALID_VALUE, GL_INVALID_INDEX);
498 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400499 return uniformBlockBindings[uniformBlockIndex];
500 }
501
502 void Program::resetUniformBlockBindings()
503 {
504 for(unsigned int blockId = 0; blockId < MAX_UNIFORM_BUFFER_BINDINGS; blockId++)
505 {
506 uniformBlockBindings[blockId] = 0;
507 }
508 }
509
510 bool Program::setUniformfv(GLint location, GLsizei count, const GLfloat *v, int numElements)
511 {
512 ASSERT(numElements >= 1 && numElements <= 4);
513
514 static GLenum floatType[] = { GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4 };
515 static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };
516
Alexis Hetuec5da192017-10-06 13:23:49 -0400517 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400518 {
519 return false;
520 }
521
522 Uniform *targetUniform = uniforms[uniformIndex[location].index];
523 targetUniform->dirty = true;
524
525 int size = targetUniform->size();
526
527 if(size == 1 && count > 1)
528 {
529 return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
530 }
531
532 count = std::min(size - (int)uniformIndex[location].element, count);
533
534 int index = numElements - 1;
535 if(targetUniform->type == floatType[index])
536 {
537 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat)* numElements,
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800538 v, numElements * sizeof(GLfloat) * count);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400539 }
540 else if(targetUniform->type == boolType[index])
541 {
542 GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * numElements;
543
544 for(int i = 0; i < count * numElements; i++)
545 {
546 boolParams[i] = (v[i] == 0.0f) ? GL_FALSE : GL_TRUE;
547 }
548 }
549 else
550 {
551 return false;
552 }
553
554 return true;
555 }
556
557 bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
558 {
559 return setUniformfv(location, count, v, 1);
560 }
561
562 bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
563 {
564 return setUniformfv(location, count, v, 2);
565 }
566
567 bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
568 {
569 return setUniformfv(location, count, v, 3);
570 }
571
572 bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
573 {
574 return setUniformfv(location, count, v, 4);
575 }
576
577 bool Program::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum type)
578 {
579 int numElements;
580 switch(type)
581 {
582 case GL_FLOAT_MAT2:
583 numElements = 4;
584 break;
585 case GL_FLOAT_MAT2x3:
586 case GL_FLOAT_MAT3x2:
587 numElements = 6;
588 break;
589 case GL_FLOAT_MAT2x4:
590 case GL_FLOAT_MAT4x2:
591 numElements = 8;
592 break;
593 case GL_FLOAT_MAT3:
594 numElements = 9;
595 break;
596 case GL_FLOAT_MAT3x4:
597 case GL_FLOAT_MAT4x3:
598 numElements = 12;
599 break;
600 case GL_FLOAT_MAT4:
601 numElements = 16;
602 break;
603 default:
604 return false;
605 }
606
Alexis Hetuec5da192017-10-06 13:23:49 -0400607 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400608 {
609 return false;
610 }
611
612 Uniform *targetUniform = uniforms[uniformIndex[location].index];
613 targetUniform->dirty = true;
614
615 if(targetUniform->type != type)
616 {
617 return false;
618 }
619
620 int size = targetUniform->size();
621
622 if(size == 1 && count > 1)
623 {
624 return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
625 }
626
627 count = std::min(size - (int)uniformIndex[location].element, count);
628
629 GLfloat* dst = reinterpret_cast<GLfloat*>(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * numElements);
630
631 if(transpose == GL_FALSE)
632 {
633 memcpy(dst, value, numElements * sizeof(GLfloat) * count);
634 }
635 else
636 {
637 const int rowSize = VariableRowCount(type);
638 const int colSize = VariableColumnCount(type);
639 for(int n = 0; n < count; ++n)
640 {
641 for(int i = 0; i < colSize; ++i)
642 {
643 for(int j = 0; j < rowSize; ++j)
644 {
645 dst[i * rowSize + j] = value[j * colSize + i];
646 }
647 }
648 dst += numElements;
649 value += numElements;
650 }
651 }
652
653
654 return true;
655 }
656
657 bool Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
658 {
659 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT2);
660 }
661
662 bool Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
663 {
664 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT2x3);
665 }
666
667 bool Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
668 {
669 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT2x4);
670 }
671
672 bool Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
673 {
674 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT3);
675 }
676
677 bool Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
678 {
679 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT3x2);
680 }
681
682 bool Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
683 {
684 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT3x4);
685 }
686
687 bool Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
688 {
689 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT4);
690 }
691
692 bool Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
693 {
694 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT4x2);
695 }
696
697 bool Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
698 {
699 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT4x3);
700 }
701
702 bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
703 {
Alexis Hetuec5da192017-10-06 13:23:49 -0400704 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400705 {
706 return false;
707 }
708
709 Uniform *targetUniform = uniforms[uniformIndex[location].index];
710 targetUniform->dirty = true;
711
712 int size = targetUniform->size();
713
714 if(size == 1 && count > 1)
715 {
716 return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
717 }
718
719 count = std::min(size - (int)uniformIndex[location].element, count);
720
Alexis Hetu3eb573f2017-11-22 13:27:03 -0500721 if(targetUniform->type == GL_INT || IsSamplerUniform(targetUniform->type))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400722 {
723 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint),
724 v, sizeof(GLint) * count);
725 }
726 else if(targetUniform->type == GL_BOOL)
727 {
728 GLboolean *boolParams = new GLboolean[count];
729
730 for(int i = 0; i < count; i++)
731 {
732 if(v[i] == 0)
733 {
734 boolParams[i] = GL_FALSE;
735 }
736 else
737 {
738 boolParams[i] = GL_TRUE;
739 }
740 }
741
742 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean),
743 boolParams, sizeof(GLboolean) * count);
744
745 delete[] boolParams;
746 }
747 else
748 {
749 return false;
750 }
751
752 return true;
753 }
754
755 bool Program::setUniformiv(GLint location, GLsizei count, const GLint *v, int numElements)
756 {
757 static GLenum intType[] = { GL_INT, GL_INT_VEC2, GL_INT_VEC3, GL_INT_VEC4 };
Nicolas Capens0bac2852016-05-07 06:09:58 -0400758 static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };
759
Alexis Hetuec5da192017-10-06 13:23:49 -0400760 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400761 {
762 return false;
763 }
764
765 Uniform *targetUniform = uniforms[uniformIndex[location].index];
766 targetUniform->dirty = true;
767
768 int size = targetUniform->size();
769
770 if(size == 1 && count > 1)
771 {
772 return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
773 }
774
775 count = std::min(size - (int)uniformIndex[location].element, count);
776
777 int index = numElements - 1;
Alexis Hetu3eb573f2017-11-22 13:27:03 -0500778 if(targetUniform->type == intType[index])
Nicolas Capens0bac2852016-05-07 06:09:58 -0400779 {
780 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint)* numElements,
781 v, numElements * sizeof(GLint)* count);
782 }
783 else if(targetUniform->type == boolType[index])
784 {
785 GLboolean *boolParams = new GLboolean[count * numElements];
786
787 for(int i = 0; i < count * numElements; i++)
788 {
789 boolParams[i] = (v[i] == 0) ? GL_FALSE : GL_TRUE;
790 }
791
792 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean)* numElements,
793 boolParams, numElements * sizeof(GLboolean)* count);
794
795 delete[] boolParams;
796 }
797 else
798 {
799 return false;
800 }
801
802 return true;
803 }
804
805 bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
806 {
807 return setUniformiv(location, count, v, 2);
808 }
809
810 bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
811 {
812 return setUniformiv(location, count, v, 3);
813 }
814
815 bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
816 {
817 return setUniformiv(location, count, v, 4);
818 }
819
820 bool Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
821 {
Alexis Hetuec5da192017-10-06 13:23:49 -0400822 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400823 {
824 return false;
825 }
826
827 Uniform *targetUniform = uniforms[uniformIndex[location].index];
828 targetUniform->dirty = true;
829
830 int size = targetUniform->size();
831
832 if(size == 1 && count > 1)
833 {
834 return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
835 }
836
837 count = std::min(size - (int)uniformIndex[location].element, count);
838
Alexis Hetu3eb573f2017-11-22 13:27:03 -0500839 if(targetUniform->type == GL_UNSIGNED_INT)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400840 {
841 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLuint),
842 v, sizeof(GLuint)* count);
843 }
844 else if(targetUniform->type == GL_BOOL)
845 {
846 GLboolean *boolParams = new GLboolean[count];
847
848 for(int i = 0; i < count; i++)
849 {
850 if(v[i] == 0)
851 {
852 boolParams[i] = GL_FALSE;
853 }
854 else
855 {
856 boolParams[i] = GL_TRUE;
857 }
858 }
859
860 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean),
861 boolParams, sizeof(GLboolean)* count);
862
863 delete[] boolParams;
864 }
865 else
866 {
867 return false;
868 }
869
870 return true;
871 }
872
873 bool Program::setUniformuiv(GLint location, GLsizei count, const GLuint *v, int numElements)
874 {
Nicolas Capens0bac2852016-05-07 06:09:58 -0400875 static GLenum uintType[] = { GL_UNSIGNED_INT, GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT_VEC3, GL_UNSIGNED_INT_VEC4 };
876 static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };
877
Alexis Hetuec5da192017-10-06 13:23:49 -0400878 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400879 {
880 return false;
881 }
882
883 Uniform *targetUniform = uniforms[uniformIndex[location].index];
884 targetUniform->dirty = true;
885
886 int size = targetUniform->size();
887
888 if(size == 1 && count > 1)
889 {
890 return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
891 }
892
893 count = std::min(size - (int)uniformIndex[location].element, count);
894
895 int index = numElements - 1;
Alexis Hetu3eb573f2017-11-22 13:27:03 -0500896 if(targetUniform->type == uintType[index])
Nicolas Capens0bac2852016-05-07 06:09:58 -0400897 {
898 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLuint)* numElements,
899 v, numElements * sizeof(GLuint)* count);
900 }
901 else if(targetUniform->type == boolType[index])
902 {
903 GLboolean *boolParams = new GLboolean[count * numElements];
904
905 for(int i = 0; i < count * numElements; i++)
906 {
907 boolParams[i] = (v[i] == 0) ? GL_FALSE : GL_TRUE;
908 }
909
910 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean)* numElements,
911 boolParams, numElements * sizeof(GLboolean)* count);
912
913 delete[] boolParams;
914 }
915 else
916 {
917 return false;
918 }
919
920 return true;
921 }
922
923 bool Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
924 {
925 return setUniformuiv(location, count, v, 2);
926 }
927
928 bool Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
929 {
930 return setUniformuiv(location, count, v, 3);
931 }
932
933 bool Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
934 {
935 return setUniformuiv(location, count, v, 4);
936 }
937
938 bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
939 {
Alexis Hetuec5da192017-10-06 13:23:49 -0400940 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400941 {
942 return false;
943 }
944
945 Uniform *targetUniform = uniforms[uniformIndex[location].index];
946 unsigned int count = UniformComponentCount(targetUniform->type);
947
948 // Sized query - ensure the provided buffer is large enough
949 if(bufSize && static_cast<unsigned int>(*bufSize) < count * sizeof(GLfloat))
950 {
951 return false;
952 }
953
954 switch(UniformComponentType(targetUniform->type))
955 {
956 case GL_BOOL:
957 {
958 GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * count;
959
960 for(unsigned int i = 0; i < count; i++)
961 {
962 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
963 }
964 }
965 break;
966 case GL_FLOAT:
967 memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLfloat),
968 count * sizeof(GLfloat));
969 break;
970 case GL_INT:
971 {
972 GLint *intParams = (GLint*)targetUniform->data + uniformIndex[location].element * count;
973
974 for(unsigned int i = 0; i < count; i++)
975 {
976 params[i] = (float)intParams[i];
977 }
978 }
979 break;
980 case GL_UNSIGNED_INT:
981 {
982 GLuint *uintParams = (GLuint*)targetUniform->data + uniformIndex[location].element * count;
983
984 for(unsigned int i = 0; i < count; i++)
985 {
986 params[i] = (float)uintParams[i];
987 }
988 }
989 break;
990 default: UNREACHABLE(targetUniform->type);
991 }
992
993 return true;
994 }
995
996 bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
997 {
Alexis Hetuec5da192017-10-06 13:23:49 -0400998 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400999 {
1000 return false;
1001 }
1002
1003 Uniform *targetUniform = uniforms[uniformIndex[location].index];
1004 unsigned int count = UniformComponentCount(targetUniform->type);
1005
1006 // Sized query - ensure the provided buffer is large enough
1007 if(bufSize && static_cast<unsigned int>(*bufSize) < count * sizeof(GLint))
1008 {
1009 return false;
1010 }
1011
1012 switch(UniformComponentType(targetUniform->type))
1013 {
1014 case GL_BOOL:
1015 {
1016 GLboolean *boolParams = targetUniform->data + uniformIndex[location].element * count;
1017
1018 for(unsigned int i = 0; i < count; i++)
1019 {
1020 params[i] = (GLint)boolParams[i];
1021 }
1022 }
1023 break;
1024 case GL_FLOAT:
1025 {
1026 GLfloat *floatParams = (GLfloat*)targetUniform->data + uniformIndex[location].element * count;
1027
1028 for(unsigned int i = 0; i < count; i++)
1029 {
1030 params[i] = (GLint)floatParams[i];
1031 }
1032 }
1033 break;
1034 case GL_INT:
1035 case GL_UNSIGNED_INT:
1036 memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLint),
1037 count * sizeof(GLint));
1038 break;
1039 default: UNREACHABLE(targetUniform->type);
1040 }
1041
1042 return true;
1043 }
1044
1045 bool Program::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
1046 {
Alexis Hetuec5da192017-10-06 13:23:49 -04001047 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -04001048 {
1049 return false;
1050 }
1051
1052 Uniform *targetUniform = uniforms[uniformIndex[location].index];
1053 unsigned int count = UniformComponentCount(targetUniform->type);
1054
1055 // Sized query - ensure the provided buffer is large enough
1056 if(bufSize && static_cast<unsigned int>(*bufSize) < count * sizeof(GLuint))
1057 {
1058 return false;
1059 }
1060
1061 switch(UniformComponentType(targetUniform->type))
1062 {
1063 case GL_BOOL:
1064 {
1065 GLboolean *boolParams = targetUniform->data + uniformIndex[location].element * count;
1066
1067 for(unsigned int i = 0; i < count; i++)
1068 {
1069 params[i] = (GLuint)boolParams[i];
1070 }
1071 }
1072 break;
1073 case GL_FLOAT:
1074 {
1075 GLfloat *floatParams = (GLfloat*)targetUniform->data + uniformIndex[location].element * count;
1076
1077 for(unsigned int i = 0; i < count; i++)
1078 {
1079 params[i] = (GLuint)floatParams[i];
1080 }
1081 }
1082 break;
1083 case GL_INT:
1084 case GL_UNSIGNED_INT:
1085 memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLuint),
1086 count * sizeof(GLuint));
1087 break;
1088 default: UNREACHABLE(targetUniform->type);
1089 }
1090
1091 return true;
1092 }
1093
1094 void Program::dirtyAllUniforms()
1095 {
1096 size_t numUniforms = uniforms.size();
1097 for(size_t index = 0; index < numUniforms; index++)
1098 {
1099 uniforms[index]->dirty = true;
1100 }
1101 }
1102
1103 // Applies all the uniforms set for this program object to the device
Ben Vanik1fd3b282017-07-10 14:08:12 -07001104 void Program::applyUniforms(Device *device)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001105 {
Alexis Hetu05c32b92016-06-23 11:32:07 -04001106 GLint numUniforms = static_cast<GLint>(uniformIndex.size());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001107 for(GLint location = 0; location < numUniforms; location++)
1108 {
Alexis Hetuec5da192017-10-06 13:23:49 -04001109 if((uniformIndex[location].element != 0) || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -04001110 {
1111 continue;
1112 }
1113
1114 Uniform *targetUniform = uniforms[uniformIndex[location].index];
1115
1116 if(targetUniform->dirty && (targetUniform->blockInfo.index == -1))
1117 {
1118 GLsizei size = targetUniform->size();
1119 GLfloat *f = (GLfloat*)targetUniform->data;
1120 GLint *i = (GLint*)targetUniform->data;
1121 GLuint *ui = (GLuint*)targetUniform->data;
1122 GLboolean *b = (GLboolean*)targetUniform->data;
1123
1124 switch(targetUniform->type)
1125 {
Ben Vanik1fd3b282017-07-10 14:08:12 -07001126 case GL_BOOL: applyUniform1bv(device, location, size, b); break;
1127 case GL_BOOL_VEC2: applyUniform2bv(device, location, size, b); break;
1128 case GL_BOOL_VEC3: applyUniform3bv(device, location, size, b); break;
1129 case GL_BOOL_VEC4: applyUniform4bv(device, location, size, b); break;
1130 case GL_FLOAT: applyUniform1fv(device, location, size, f); break;
1131 case GL_FLOAT_VEC2: applyUniform2fv(device, location, size, f); break;
1132 case GL_FLOAT_VEC3: applyUniform3fv(device, location, size, f); break;
1133 case GL_FLOAT_VEC4: applyUniform4fv(device, location, size, f); break;
1134 case GL_FLOAT_MAT2: applyUniformMatrix2fv(device, location, size, f); break;
1135 case GL_FLOAT_MAT2x3: applyUniformMatrix2x3fv(device, location, size, f); break;
1136 case GL_FLOAT_MAT2x4: applyUniformMatrix2x4fv(device, location, size, f); break;
1137 case GL_FLOAT_MAT3x2: applyUniformMatrix3x2fv(device, location, size, f); break;
1138 case GL_FLOAT_MAT3: applyUniformMatrix3fv(device, location, size, f); break;
1139 case GL_FLOAT_MAT3x4: applyUniformMatrix3x4fv(device, location, size, f); break;
1140 case GL_FLOAT_MAT4x2: applyUniformMatrix4x2fv(device, location, size, f); break;
1141 case GL_FLOAT_MAT4x3: applyUniformMatrix4x3fv(device, location, size, f); break;
1142 case GL_FLOAT_MAT4: applyUniformMatrix4fv(device, location, size, f); break;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001143 case GL_SAMPLER_2D:
1144 case GL_SAMPLER_CUBE:
1145 case GL_SAMPLER_EXTERNAL_OES:
1146 case GL_SAMPLER_3D_OES:
1147 case GL_SAMPLER_2D_ARRAY:
1148 case GL_SAMPLER_2D_SHADOW:
1149 case GL_SAMPLER_CUBE_SHADOW:
1150 case GL_SAMPLER_2D_ARRAY_SHADOW:
1151 case GL_INT_SAMPLER_2D:
1152 case GL_UNSIGNED_INT_SAMPLER_2D:
1153 case GL_INT_SAMPLER_CUBE:
1154 case GL_UNSIGNED_INT_SAMPLER_CUBE:
1155 case GL_INT_SAMPLER_3D:
1156 case GL_UNSIGNED_INT_SAMPLER_3D:
1157 case GL_INT_SAMPLER_2D_ARRAY:
1158 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
Ben Vanik1fd3b282017-07-10 14:08:12 -07001159 case GL_INT: applyUniform1iv(device, location, size, i); break;
1160 case GL_INT_VEC2: applyUniform2iv(device, location, size, i); break;
1161 case GL_INT_VEC3: applyUniform3iv(device, location, size, i); break;
1162 case GL_INT_VEC4: applyUniform4iv(device, location, size, i); break;
1163 case GL_UNSIGNED_INT: applyUniform1uiv(device, location, size, ui); break;
1164 case GL_UNSIGNED_INT_VEC2: applyUniform2uiv(device, location, size, ui); break;
1165 case GL_UNSIGNED_INT_VEC3: applyUniform3uiv(device, location, size, ui); break;
1166 case GL_UNSIGNED_INT_VEC4: applyUniform4uiv(device, location, size, ui); break;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001167 default:
1168 UNREACHABLE(targetUniform->type);
1169 }
1170
1171 targetUniform->dirty = false;
1172 }
1173 }
1174 }
1175
Ben Vanik1fd3b282017-07-10 14:08:12 -07001176 void Program::applyUniformBuffers(Device *device, BufferBinding* uniformBuffers)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001177 {
1178 GLint vertexUniformBuffers[MAX_UNIFORM_BUFFER_BINDINGS];
1179 GLint fragmentUniformBuffers[MAX_UNIFORM_BUFFER_BINDINGS];
1180
1181 for(unsigned int bufferBindingIndex = 0; bufferBindingIndex < MAX_UNIFORM_BUFFER_BINDINGS; bufferBindingIndex++)
1182 {
1183 vertexUniformBuffers[bufferBindingIndex] = -1;
1184 }
1185
1186 for(unsigned int bufferBindingIndex = 0; bufferBindingIndex < MAX_UNIFORM_BUFFER_BINDINGS; bufferBindingIndex++)
1187 {
1188 fragmentUniformBuffers[bufferBindingIndex] = -1;
1189 }
1190
1191 int vertexUniformBufferIndex = 0;
1192 int fragmentUniformBufferIndex = 0;
1193 for(unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlocks.size(); uniformBlockIndex++)
1194 {
1195 UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];
1196
1197 // Unnecessary to apply an unreferenced standard or shared UBO
1198 if(!uniformBlock.isReferencedByVertexShader() && !uniformBlock.isReferencedByFragmentShader())
1199 {
1200 continue;
1201 }
1202
1203 GLuint blockBinding = uniformBlockBindings[uniformBlockIndex];
1204
1205 if(uniformBlock.isReferencedByVertexShader())
1206 {
1207 vertexUniformBuffers[vertexUniformBufferIndex++] = blockBinding;
1208 }
1209
1210 if(uniformBlock.isReferencedByFragmentShader())
1211 {
1212 fragmentUniformBuffers[fragmentUniformBufferIndex++] = blockBinding;
1213 }
1214 }
1215
1216 for(unsigned int bufferBindingIndex = 0; bufferBindingIndex < MAX_UNIFORM_BUFFER_BINDINGS; bufferBindingIndex++)
1217 {
1218 int index = vertexUniformBuffers[bufferBindingIndex];
Alexis Hetu20c0f652016-09-21 09:11:44 -04001219 Buffer* vsBuffer = (index != -1) ? (Buffer*)uniformBuffers[index].get() : nullptr;
1220 device->VertexProcessor::setUniformBuffer(bufferBindingIndex,
1221 vsBuffer ? vsBuffer->getResource() : nullptr, (index != -1) ? uniformBuffers[index].getOffset() : 0);
1222 index = fragmentUniformBuffers[bufferBindingIndex];
1223 Buffer* psBuffer = (index != -1) ? (Buffer*)uniformBuffers[index].get() : nullptr;
1224 device->PixelProcessor::setUniformBuffer(bufferBindingIndex,
1225 psBuffer ? psBuffer->getResource() : nullptr, (index != -1) ? uniformBuffers[index].getOffset() : 0);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001226 }
1227 }
1228
Ben Vanik1fd3b282017-07-10 14:08:12 -07001229 void Program::applyTransformFeedback(Device *device, TransformFeedback* transformFeedback)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001230 {
1231 // Make sure the flags will fit in a 64 bit unsigned int variable
1232 ASSERT(sw::max<int>(MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS) <= 64);
1233
1234 BufferBinding* transformFeedbackBuffers = (transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused()) ? transformFeedback->getBuffers() : nullptr;
1235
1236 uint64_t enableTransformFeedback = 0;
1237 if(!transformFeedbackBuffers)
1238 {
1239 for(unsigned int index = 0; index < sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; ++index)
1240 {
1241 device->VertexProcessor::setTransformFeedbackBuffer(index, nullptr, 0, 0, 0, 0, 0);
1242 }
1243 device->VertexProcessor::enableTransformFeedback(enableTransformFeedback);
1244 return;
1245 }
1246
Alexis Hetu05c32b92016-06-23 11:32:07 -04001247 unsigned int maxVaryings = static_cast<unsigned int>(transformFeedbackLinkedVaryings.size());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001248 switch(transformFeedbackBufferMode)
1249 {
1250 case GL_SEPARATE_ATTRIBS:
1251 {
1252 maxVaryings = sw::min(maxVaryings, (unsigned int)MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS);
1253 // Attribs go to separate buffers
1254 for(unsigned int index = 0; index < maxVaryings; ++index)
1255 {
1256 int size = transformFeedbackLinkedVaryings[index].size;
1257 int rowCount = VariableRowCount(transformFeedbackLinkedVaryings[index].type);
1258 int colCount = VariableColumnCount(transformFeedbackLinkedVaryings[index].type);
1259 int nbRegs = rowCount > 1 ? colCount * size : size;
1260 int nbComponentsPerReg = rowCount > 1 ? rowCount : colCount;
1261 int componentStride = rowCount * colCount * size;
1262 int baseOffset = transformFeedback->vertexOffset() * componentStride * sizeof(float);
1263 device->VertexProcessor::setTransformFeedbackBuffer(index,
1264 transformFeedbackBuffers[index].get()->getResource(),
1265 transformFeedbackBuffers[index].getOffset() + baseOffset,
1266 transformFeedbackLinkedVaryings[index].reg * 4 + transformFeedbackLinkedVaryings[index].col,
1267 nbRegs, nbComponentsPerReg, componentStride);
1268 enableTransformFeedback |= 1ULL << index;
1269 }
1270 }
1271 break;
1272 case GL_INTERLEAVED_ATTRIBS:
1273 {
1274 // OpenGL ES 3.0.4 spec, section 2.15.2:
1275 // In INTERLEAVED_ATTRIBS mode, the values of one or more output variables
1276 // written by a vertex shader are written, interleaved, into the buffer object
1277 // bound to the first transform feedback binding point (index = 0).
1278 sw::Resource* resource = transformFeedbackBuffers[0].get()->getResource();
Alexis Hetu05c32b92016-06-23 11:32:07 -04001279 int componentStride = static_cast<int>(totalLinkedVaryingsComponents);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001280 int baseOffset = transformFeedbackBuffers[0].getOffset() + (transformFeedback->vertexOffset() * componentStride * sizeof(float));
1281 maxVaryings = sw::min(maxVaryings, (unsigned int)sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS);
Alexis Hetu05c32b92016-06-23 11:32:07 -04001282 int totalComponents = 0;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001283 for(unsigned int index = 0; index < maxVaryings; ++index)
1284 {
1285 int size = transformFeedbackLinkedVaryings[index].size;
1286 int rowCount = VariableRowCount(transformFeedbackLinkedVaryings[index].type);
1287 int colCount = VariableColumnCount(transformFeedbackLinkedVaryings[index].type);
1288 int nbRegs = rowCount > 1 ? colCount * size : size;
1289 int nbComponentsPerReg = rowCount > 1 ? rowCount : colCount;
1290 device->VertexProcessor::setTransformFeedbackBuffer(index, resource,
1291 baseOffset + (totalComponents * sizeof(float)),
1292 transformFeedbackLinkedVaryings[index].reg * 4 + transformFeedbackLinkedVaryings[index].col,
1293 nbRegs, nbComponentsPerReg, componentStride);
1294 totalComponents += rowCount * colCount * size;
1295 enableTransformFeedback |= 1ULL << index;
1296 }
1297 }
1298 break;
1299 default:
1300 UNREACHABLE(transformFeedbackBufferMode);
1301 break;
1302 }
1303
1304 // Unset all other transform feedback buffers
1305 for(unsigned int index = maxVaryings; index < sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; ++index)
1306 {
1307 device->VertexProcessor::setTransformFeedbackBuffer(index, nullptr, 0, 0, 0, 0, 0);
1308 }
1309
1310 device->VertexProcessor::enableTransformFeedback(enableTransformFeedback);
1311 }
1312
1313 bool Program::linkVaryings()
1314 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001315 glsl::VaryingList &psVaryings = fragmentShader->varyings;
1316 glsl::VaryingList &vsVaryings = vertexShader->varyings;
1317
1318 for(auto const &input : psVaryings)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001319 {
1320 bool matched = false;
1321
Alexis Hetu23f54d72017-12-05 16:03:51 -05001322 for(auto const &output : vsVaryings)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001323 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001324 if(output.name == input.name)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001325 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001326 if(output.type != input.type || output.size() != input.size())
Nicolas Capens0bac2852016-05-07 06:09:58 -04001327 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001328 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output.name.c_str());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001329
1330 return false;
1331 }
1332
1333 matched = true;
1334 break;
1335 }
1336 }
1337
1338 if(!matched)
1339 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001340 appendToInfoLog("Fragment varying %s does not match any vertex varying", input.name.c_str());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001341
1342 return false;
1343 }
1344 }
1345
Alexis Hetu23f54d72017-12-05 16:03:51 -05001346 for(auto const &output : vsVaryings)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001347 {
Alexis Hetu144974d2016-04-05 17:31:32 -04001348 bool matched = false;
1349
Alexis Hetu23f54d72017-12-05 16:03:51 -05001350 for(auto const &input : psVaryings)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001351 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001352 if(output.name == input.name)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001353 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001354 int in = input.reg;
1355 int out = output.reg;
1356 int components = VariableRegisterSize(output.type);
1357 int registers = VariableRegisterCount(output.type) * output.size();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001358
1359 ASSERT(in >= 0);
1360
1361 if(in + registers > MAX_VARYING_VECTORS)
1362 {
1363 appendToInfoLog("Too many varyings");
1364 return false;
1365 }
1366
1367 if(out >= 0)
1368 {
1369 if(out + registers > MAX_VARYING_VECTORS)
1370 {
1371 appendToInfoLog("Too many varyings");
1372 return false;
1373 }
1374
1375 for(int i = 0; i < registers; i++)
1376 {
Alexis Hetu02ad0aa2016-08-02 11:18:14 -04001377 vertexBinary->setOutput(out + i, components, sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i, pixelBinary->getInput(in + i, 0).flat));
Nicolas Capens0bac2852016-05-07 06:09:58 -04001378 }
1379 }
1380 else // Vertex varying is declared but not written to
1381 {
1382 for(int i = 0; i < registers; i++)
1383 {
Alexis Hetu02ad0aa2016-08-02 11:18:14 -04001384 pixelBinary->setInput(in + i, components, sw::Shader::Semantic());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001385 }
1386 }
1387
Alexis Hetu144974d2016-04-05 17:31:32 -04001388 matched = true;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001389 break;
1390 }
1391 }
Alexis Hetu144974d2016-04-05 17:31:32 -04001392
Alexis Hetuec92f3c2017-05-23 17:10:09 -04001393 if(!matched)
Alexis Hetu144974d2016-04-05 17:31:32 -04001394 {
Alexis Hetuec92f3c2017-05-23 17:10:09 -04001395 // For openGL ES 3.0, we need to still add the vertex shader outputs for unmatched varyings, for transform feedback.
1396 for(const std::string &indexedTfVaryingName : transformFeedbackVaryings)
Alexis Hetu144974d2016-04-05 17:31:32 -04001397 {
Alexis Hetuec92f3c2017-05-23 17:10:09 -04001398 std::string tfVaryingName = es2::ParseUniformName(indexedTfVaryingName, nullptr);
Alexis Hetu144974d2016-04-05 17:31:32 -04001399
Alexis Hetu23f54d72017-12-05 16:03:51 -05001400 if(tfVaryingName == output.name)
Alexis Hetu144974d2016-04-05 17:31:32 -04001401 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001402 int out = output.reg;
1403 int components = VariableRegisterSize(output.type);
1404 int registers = VariableRegisterCount(output.type) * output.size();
Alexis Hetuec92f3c2017-05-23 17:10:09 -04001405
1406 if(out >= 0)
1407 {
1408 if(out + registers > MAX_VARYING_VECTORS)
1409 {
1410 appendToInfoLog("Too many varyings");
1411 return false;
1412 }
1413
1414 for(int i = 0; i < registers; i++)
1415 {
1416 vertexBinary->setOutput(out + i, components, sw::Shader::Semantic(sw::Shader::USAGE_COLOR));
1417 }
1418 }
1419 break;
Alexis Hetu144974d2016-04-05 17:31:32 -04001420 }
1421 }
1422 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001423 }
1424
1425 return true;
1426 }
1427
1428 bool Program::linkTransformFeedback()
1429 {
1430 size_t totalComponents = 0;
1431 totalLinkedVaryingsComponents = 0;
1432
1433 std::set<std::string> uniqueNames;
1434
1435 for(const std::string &indexedTfVaryingName : transformFeedbackVaryings)
1436 {
Alexis Hetu53977f12016-06-27 16:04:31 -04001437 unsigned int subscript = GL_INVALID_INDEX;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001438 std::string tfVaryingName = es2::ParseUniformName(indexedTfVaryingName, &subscript);
1439 bool hasSubscript = (subscript != GL_INVALID_INDEX);
1440
1441 if(tfVaryingName.find('[') != std::string::npos)
1442 {
1443 appendToInfoLog("Capture of array sub-elements is undefined and not supported.");
1444 return false;
1445 }
1446
1447 bool found = false;
1448 for(const glsl::Varying varying : vertexShader->varyings)
1449 {
1450 if(tfVaryingName == varying.name)
1451 {
1452 if(uniqueNames.count(indexedTfVaryingName) > 0)
1453 {
1454 appendToInfoLog("Two transform feedback varyings specify the same output variable (%s)", indexedTfVaryingName.c_str());
1455 return false;
1456 }
1457 uniqueNames.insert(indexedTfVaryingName);
1458
1459 if(hasSubscript && ((static_cast<int>(subscript)) >= varying.size()))
1460 {
1461 appendToInfoLog("Specified transform feedback varying index out of bounds (%s)", indexedTfVaryingName.c_str());
1462 return false;
1463 }
1464
Alexis Hetu05c32b92016-06-23 11:32:07 -04001465 int size = hasSubscript ? 1 : varying.size();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001466
Alexis Hetu05c32b92016-06-23 11:32:07 -04001467 int rowCount = VariableRowCount(varying.type);
1468 int colCount = VariableColumnCount(varying.type);
1469 int componentCount = rowCount * colCount * size;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001470 if(transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
1471 componentCount > sw::MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS)
1472 {
1473 appendToInfoLog("Transform feedback varying's %s components (%d) exceed the maximum separate components (%d).",
1474 varying.name.c_str(), componentCount, sw::MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS);
1475 return false;
1476 }
1477
1478 totalComponents += componentCount;
1479
1480 int reg = varying.reg;
1481 if(hasSubscript)
1482 {
1483 reg += rowCount > 1 ? colCount * subscript : subscript;
1484 }
1485 int col = varying.col;
1486 if(tfVaryingName == "gl_PointSize")
1487 {
1488 // Point size is stored in the y element of the vector, not the x element
1489 col = 1; // FIXME: varying.col could already contain this information
1490 }
1491 transformFeedbackLinkedVaryings.push_back(LinkedVarying(varying.name, varying.type, size, reg, col));
1492
1493 found = true;
1494 break;
1495 }
1496 }
1497
1498 if(!found)
1499 {
1500 appendToInfoLog("Transform feedback varying %s does not exist in the vertex shader.", tfVaryingName.c_str());
1501 return false;
1502 }
1503 }
1504
1505 if(transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
1506 totalComponents > sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS)
1507 {
1508 appendToInfoLog("Transform feedback varying total components (%d) exceed the maximum separate components (%d).",
1509 totalComponents, sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS);
1510 return false;
1511 }
1512
1513 totalLinkedVaryingsComponents = totalComponents;
1514
1515 return true;
1516 }
1517
1518 // Links the code of the vertex and pixel shader by matching up their varyings,
1519 // compiling them into binaries, determining the attribute mappings, and collecting
1520 // a list of uniforms
1521 void Program::link()
1522 {
1523 unlink();
1524
1525 resetUniformBlockBindings();
1526
1527 if(!fragmentShader || !fragmentShader->isCompiled())
1528 {
1529 return;
1530 }
1531
1532 if(!vertexShader || !vertexShader->isCompiled())
1533 {
1534 return;
1535 }
1536
1537 vertexBinary = new sw::VertexShader(vertexShader->getVertexShader());
1538 pixelBinary = new sw::PixelShader(fragmentShader->getPixelShader());
1539
1540 if(!linkVaryings())
1541 {
1542 return;
1543 }
1544
1545 if(!linkAttributes())
1546 {
1547 return;
1548 }
1549
1550 // Link uniform blocks before uniforms to make it easy to assign block indices to fields
1551 if(!linkUniformBlocks(vertexShader, fragmentShader))
1552 {
1553 return;
1554 }
1555
1556 if(!linkUniforms(fragmentShader))
1557 {
1558 return;
1559 }
1560
1561 if(!linkUniforms(vertexShader))
1562 {
1563 return;
1564 }
1565
1566 if(!linkTransformFeedback())
1567 {
1568 return;
1569 }
1570
1571 linked = true; // Success
1572 }
1573
1574 // Determines the mapping between GL attributes and vertex stream usage indices
1575 bool Program::linkAttributes()
1576 {
1577 unsigned int usedLocations = 0;
1578
1579 // Link attributes that have a binding location
Alexis Hetu23f54d72017-12-05 16:03:51 -05001580 for(auto const &attribute : vertexShader->activeAttributes)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001581 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001582 int location = (attributeBinding.find(attribute.name) != attributeBinding.end()) ? attributeBinding[attribute.name] : -1;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001583
1584 if(location != -1) // Set by glBindAttribLocation
1585 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001586 int rows = VariableRegisterCount(attribute.type);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001587
1588 if(rows + location > MAX_VERTEX_ATTRIBS)
1589 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001590 appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001591 return false;
1592 }
1593
1594 // In GLSL 3.00, attribute aliasing produces a link error
1595 // In GLSL 1.00, attribute aliasing is allowed
Alexis Hetu23f54d72017-12-05 16:03:51 -05001596 if(vertexShader->getShaderVersion() >= 300)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001597 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001598 for(auto const &it : linkedAttribute)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001599 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001600 int itLocStart = getAttributeBinding(it);
1601 ASSERT(itLocStart >= 0);
1602 int itLocEnd = itLocStart + VariableRegisterCount(it.type);
1603 for(int i = 0; i < rows; i++)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001604 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001605 int loc = location + i;
1606 if((loc >= itLocStart) && (loc < itLocEnd))
1607 {
1608 appendToInfoLog("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), it.name.c_str(), location);
1609 return false;
1610 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001611 }
1612 }
1613 }
1614
Alexis Hetu23f54d72017-12-05 16:03:51 -05001615 linkedAttributeLocation[attribute.name] = location;
1616 linkedAttribute.push_back(attribute);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001617 for(int i = 0; i < rows; i++)
1618 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04001619 usedLocations |= 1 << (location + i);
1620 }
1621 }
1622 }
1623
1624 // Link attributes that don't have a binding location
Alexis Hetu23f54d72017-12-05 16:03:51 -05001625 for(auto const &attribute : vertexShader->activeAttributes)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001626 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001627 int location = (attributeBinding.find(attribute.name) != attributeBinding.end()) ? attributeBinding[attribute.name] : -1;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001628
1629 if(location == -1) // Not set by glBindAttribLocation
1630 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001631 int rows = VariableRegisterCount(attribute.type);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001632 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1633
1634 if(availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1635 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001636 appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001637 return false; // Fail to link
1638 }
1639
Alexis Hetu23f54d72017-12-05 16:03:51 -05001640 linkedAttributeLocation[attribute.name] = availableIndex;
1641 linkedAttribute.push_back(attribute);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001642 }
1643 }
1644
Alexis Hetu23f54d72017-12-05 16:03:51 -05001645 for(auto const &it : linkedAttribute)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001646 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001647 int location = getAttributeBinding(it);
1648 ASSERT(location >= 0);
1649 int index = vertexShader->getSemanticIndex(it.name);
1650 int rows = std::max(VariableRegisterCount(it.type), 1);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001651
1652 for(int r = 0; r < rows; r++)
1653 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001654 attributeStream[r + location] = index++;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001655 }
1656 }
1657
1658 return true;
1659 }
1660
1661 int Program::getAttributeBinding(const glsl::Attribute &attribute)
1662 {
1663 if(attribute.location != -1)
1664 {
1665 return attribute.location;
1666 }
1667
Nicolas Capenscbd20d92017-12-19 00:07:50 -05001668 std::map<std::string, GLuint>::const_iterator it = linkedAttributeLocation.find(attribute.name);
Alexis Hetu23f54d72017-12-05 16:03:51 -05001669 if(it != linkedAttributeLocation.end())
Nicolas Capens0bac2852016-05-07 06:09:58 -04001670 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001671 return it->second;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001672 }
1673
1674 return -1;
1675 }
1676
1677 bool Program::linkUniforms(const Shader *shader)
1678 {
1679 const glsl::ActiveUniforms &activeUniforms = shader->activeUniforms;
1680
1681 for(unsigned int uniformIndex = 0; uniformIndex < activeUniforms.size(); uniformIndex++)
1682 {
1683 const glsl::Uniform &uniform = activeUniforms[uniformIndex];
1684
1685 unsigned int blockIndex = GL_INVALID_INDEX;
1686 if(uniform.blockId >= 0)
1687 {
1688 const glsl::ActiveUniformBlocks &activeUniformBlocks = shader->activeUniformBlocks;
1689 ASSERT(static_cast<size_t>(uniform.blockId) < activeUniformBlocks.size());
1690 blockIndex = getUniformBlockIndex(activeUniformBlocks[uniform.blockId].name);
1691 ASSERT(blockIndex != GL_INVALID_INDEX);
1692 }
1693 if(!defineUniform(shader->getType(), uniform.type, uniform.precision, uniform.name, uniform.arraySize, uniform.registerIndex, Uniform::BlockInfo(uniform, blockIndex)))
1694 {
1695 return false;
1696 }
1697 }
1698
1699 return true;
1700 }
1701
1702 bool Program::defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, int registerIndex, const Uniform::BlockInfo& blockInfo)
1703 {
1704 if(IsSamplerUniform(type))
1705 {
1706 int index = registerIndex;
1707
1708 do
1709 {
1710 if(shader == GL_VERTEX_SHADER)
1711 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00001712 if(index < MAX_VERTEX_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001713 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00001714 samplersVS[index].active = true;
1715
Nicolas Capens0bac2852016-05-07 06:09:58 -04001716 switch(type)
1717 {
1718 default: UNREACHABLE(type);
1719 case GL_INT_SAMPLER_2D:
1720 case GL_UNSIGNED_INT_SAMPLER_2D:
1721 case GL_SAMPLER_2D_SHADOW:
1722 case GL_SAMPLER_2D: samplersVS[index].textureType = TEXTURE_2D; break;
1723 case GL_INT_SAMPLER_CUBE:
1724 case GL_UNSIGNED_INT_SAMPLER_CUBE:
1725 case GL_SAMPLER_CUBE_SHADOW:
1726 case GL_SAMPLER_CUBE: samplersVS[index].textureType = TEXTURE_CUBE; break;
1727 case GL_INT_SAMPLER_3D:
1728 case GL_UNSIGNED_INT_SAMPLER_3D:
1729 case GL_SAMPLER_3D_OES: samplersVS[index].textureType = TEXTURE_3D; break;
1730 case GL_SAMPLER_EXTERNAL_OES: samplersVS[index].textureType = TEXTURE_EXTERNAL; break;
1731 case GL_INT_SAMPLER_2D_ARRAY:
1732 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
1733 case GL_SAMPLER_2D_ARRAY_SHADOW:
1734 case GL_SAMPLER_2D_ARRAY: samplersVS[index].textureType = TEXTURE_2D_ARRAY; break;
1735 }
1736
1737 samplersVS[index].logicalTextureUnit = 0;
1738 }
1739 else
1740 {
1741 appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", MAX_VERTEX_TEXTURE_IMAGE_UNITS);
1742 return false;
1743 }
1744 }
1745 else if(shader == GL_FRAGMENT_SHADER)
1746 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00001747 if(index < MAX_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001748 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00001749 samplersPS[index].active = true;
1750
Nicolas Capens0bac2852016-05-07 06:09:58 -04001751 switch(type)
1752 {
1753 default: UNREACHABLE(type);
1754 case GL_INT_SAMPLER_2D:
1755 case GL_UNSIGNED_INT_SAMPLER_2D:
1756 case GL_SAMPLER_2D_SHADOW:
1757 case GL_SAMPLER_2D: samplersPS[index].textureType = TEXTURE_2D; break;
1758 case GL_INT_SAMPLER_CUBE:
1759 case GL_UNSIGNED_INT_SAMPLER_CUBE:
1760 case GL_SAMPLER_CUBE_SHADOW:
1761 case GL_SAMPLER_CUBE: samplersPS[index].textureType = TEXTURE_CUBE; break;
1762 case GL_INT_SAMPLER_3D:
1763 case GL_UNSIGNED_INT_SAMPLER_3D:
1764 case GL_SAMPLER_3D_OES: samplersPS[index].textureType = TEXTURE_3D; break;
1765 case GL_SAMPLER_EXTERNAL_OES: samplersPS[index].textureType = TEXTURE_EXTERNAL; break;
1766 case GL_INT_SAMPLER_2D_ARRAY:
1767 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
1768 case GL_SAMPLER_2D_ARRAY_SHADOW:
1769 case GL_SAMPLER_2D_ARRAY: samplersPS[index].textureType = TEXTURE_2D_ARRAY; break;
1770 }
1771
1772 samplersPS[index].logicalTextureUnit = 0;
1773 }
1774 else
1775 {
1776 appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
1777 return false;
1778 }
1779 }
1780 else UNREACHABLE(shader);
1781
1782 index++;
1783 }
1784 while(index < registerIndex + static_cast<int>(arraySize));
1785 }
1786
1787 Uniform *uniform = 0;
1788 GLint location = getUniformLocation(name);
1789
1790 if(location >= 0) // Previously defined, types must match
1791 {
1792 uniform = uniforms[uniformIndex[location].index];
1793
1794 if(uniform->type != type)
1795 {
1796 appendToInfoLog("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
1797 return false;
1798 }
1799
1800 if(uniform->precision != precision)
1801 {
1802 appendToInfoLog("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
1803 return false;
1804 }
1805 }
1806 else
1807 {
1808 uniform = new Uniform(type, precision, name, arraySize, blockInfo);
1809 }
1810
1811 if(!uniform)
1812 {
1813 return false;
1814 }
1815
1816 if(shader == GL_VERTEX_SHADER)
1817 {
1818 uniform->vsRegisterIndex = registerIndex;
1819 }
1820 else if(shader == GL_FRAGMENT_SHADER)
1821 {
1822 uniform->psRegisterIndex = registerIndex;
1823 }
1824 else UNREACHABLE(shader);
1825
Alexis Hetuec5da192017-10-06 13:23:49 -04001826 if(!isUniformDefined(name))
Nicolas Capens0bac2852016-05-07 06:09:58 -04001827 {
1828 uniforms.push_back(uniform);
Alexis Hetuec5da192017-10-06 13:23:49 -04001829 unsigned int index = (blockInfo.index == -1) ? static_cast<unsigned int>(uniforms.size() - 1) : GL_INVALID_INDEX;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001830
1831 for(int i = 0; i < uniform->size(); i++)
1832 {
1833 uniformIndex.push_back(UniformLocation(name, i, index));
1834 }
1835 }
1836
1837 if(shader == GL_VERTEX_SHADER)
1838 {
1839 if(registerIndex + uniform->registerCount() > MAX_VERTEX_UNIFORM_VECTORS)
1840 {
1841 appendToInfoLog("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%d)", MAX_VERTEX_UNIFORM_VECTORS);
1842 return false;
1843 }
1844 }
1845 else if(shader == GL_FRAGMENT_SHADER)
1846 {
1847 if(registerIndex + uniform->registerCount() > MAX_FRAGMENT_UNIFORM_VECTORS)
1848 {
1849 appendToInfoLog("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%d)", MAX_FRAGMENT_UNIFORM_VECTORS);
1850 return false;
1851 }
1852 }
1853 else UNREACHABLE(shader);
1854
1855 return true;
1856 }
1857
1858 bool Program::areMatchingUniformBlocks(const glsl::UniformBlock &block1, const glsl::UniformBlock &block2, const Shader *shader1, const Shader *shader2)
1859 {
1860 // validate blocks for the same member types
1861 if(block1.fields.size() != block2.fields.size())
1862 {
1863 return false;
1864 }
1865 if(block1.arraySize != block2.arraySize)
1866 {
1867 return false;
1868 }
1869 if(block1.layout != block2.layout || block1.isRowMajorLayout != block2.isRowMajorLayout)
1870 {
1871 return false;
1872 }
1873 const size_t numBlockMembers = block1.fields.size();
1874 for(size_t blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
1875 {
1876 const glsl::Uniform& member1 = shader1->activeUniforms[block1.fields[blockMemberIndex]];
1877 const glsl::Uniform& member2 = shader2->activeUniforms[block2.fields[blockMemberIndex]];
1878 if(member1.name != member2.name ||
1879 member1.arraySize != member2.arraySize ||
1880 member1.precision != member2.precision ||
1881 member1.type != member2.type)
1882 {
1883 return false;
1884 }
1885 }
1886 return true;
1887 }
1888
1889 bool Program::linkUniformBlocks(const Shader *vertexShader, const Shader *fragmentShader)
1890 {
1891 const glsl::ActiveUniformBlocks &vertexUniformBlocks = vertexShader->activeUniformBlocks;
1892 const glsl::ActiveUniformBlocks &fragmentUniformBlocks = fragmentShader->activeUniformBlocks;
1893 // Check that interface blocks defined in the vertex and fragment shaders are identical
1894 typedef std::map<std::string, const glsl::UniformBlock*> UniformBlockMap;
1895 UniformBlockMap linkedUniformBlocks;
1896 for(unsigned int blockIndex = 0; blockIndex < vertexUniformBlocks.size(); blockIndex++)
1897 {
1898 const glsl::UniformBlock &vertexUniformBlock = vertexUniformBlocks[blockIndex];
1899 linkedUniformBlocks[vertexUniformBlock.name] = &vertexUniformBlock;
1900 }
1901 for(unsigned int blockIndex = 0; blockIndex < fragmentUniformBlocks.size(); blockIndex++)
1902 {
1903 const glsl::UniformBlock &fragmentUniformBlock = fragmentUniformBlocks[blockIndex];
1904 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentUniformBlock.name);
1905 if(entry != linkedUniformBlocks.end())
1906 {
1907 const glsl::UniformBlock &vertexUniformBlock = *entry->second;
1908 if(!areMatchingUniformBlocks(vertexUniformBlock, fragmentUniformBlock, vertexShader, fragmentShader))
1909 {
1910 return false;
1911 }
1912 }
1913 }
1914 for(unsigned int blockIndex = 0; blockIndex < vertexUniformBlocks.size(); blockIndex++)
1915 {
1916 const glsl::UniformBlock &uniformBlock = vertexUniformBlocks[blockIndex];
1917 if(!defineUniformBlock(vertexShader, uniformBlock))
1918 {
1919 return false;
1920 }
1921 }
1922 for(unsigned int blockIndex = 0; blockIndex < fragmentUniformBlocks.size(); blockIndex++)
1923 {
1924 const glsl::UniformBlock &uniformBlock = fragmentUniformBlocks[blockIndex];
1925 if(!defineUniformBlock(fragmentShader, uniformBlock))
1926 {
1927 return false;
1928 }
1929 }
1930 return true;
1931 }
1932
1933 bool Program::defineUniformBlock(const Shader *shader, const glsl::UniformBlock &block)
1934 {
1935 GLuint blockIndex = getUniformBlockIndex(block.name);
1936
1937 if(blockIndex == GL_INVALID_INDEX)
1938 {
1939 const std::vector<int>& fields = block.fields;
1940 std::vector<unsigned int> memberUniformIndexes;
1941 for(size_t i = 0; i < fields.size(); ++i)
1942 {
1943 memberUniformIndexes.push_back(fields[i]);
1944 }
1945
1946 if(block.arraySize > 0)
1947 {
1948 int regIndex = block.registerIndex;
1949 int regInc = block.dataSize / (glsl::BlockLayoutEncoder::BytesPerComponent * glsl::BlockLayoutEncoder::ComponentsPerRegister);
1950 for(unsigned int i = 0; i < block.arraySize; ++i, regIndex += regInc)
1951 {
1952 uniformBlocks.push_back(new UniformBlock(block.name, i, block.dataSize, memberUniformIndexes));
1953 uniformBlocks[uniformBlocks.size() - 1]->setRegisterIndex(shader->getType(), regIndex);
1954 }
1955 }
1956 else
1957 {
1958 uniformBlocks.push_back(new UniformBlock(block.name, GL_INVALID_INDEX, block.dataSize, memberUniformIndexes));
1959 uniformBlocks[uniformBlocks.size() - 1]->setRegisterIndex(shader->getType(), block.registerIndex);
1960 }
1961 }
1962 else
1963 {
1964 int regIndex = block.registerIndex;
1965 int regInc = block.dataSize / (glsl::BlockLayoutEncoder::BytesPerComponent * glsl::BlockLayoutEncoder::ComponentsPerRegister);
1966 int nbBlocks = (block.arraySize > 0) ? block.arraySize : 1;
1967 for(int i = 0; i < nbBlocks; ++i, regIndex += regInc)
1968 {
1969 uniformBlocks[blockIndex + i]->setRegisterIndex(shader->getType(), regIndex);
1970 }
1971 }
1972
1973 return true;
1974 }
1975
Ben Vanik1fd3b282017-07-10 14:08:12 -07001976 bool Program::applyUniform(Device *device, GLint location, float* data)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001977 {
1978 Uniform *targetUniform = uniforms[uniformIndex[location].index];
1979
1980 if(targetUniform->psRegisterIndex != -1)
1981 {
1982 device->setPixelShaderConstantF(targetUniform->psRegisterIndex, data, targetUniform->registerCount());
1983 }
1984
1985 if(targetUniform->vsRegisterIndex != -1)
1986 {
1987 device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, data, targetUniform->registerCount());
1988 }
1989
1990 return true;
1991 }
1992
Ben Vanik1fd3b282017-07-10 14:08:12 -07001993 bool Program::applyUniform1bv(Device *device, GLint location, GLsizei count, const GLboolean *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001994 {
1995 int vector[MAX_UNIFORM_VECTORS][4];
1996
1997 for(int i = 0; i < count; i++)
1998 {
1999 vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2000 vector[i][1] = 0;
2001 vector[i][2] = 0;
2002 vector[i][3] = 0;
2003
2004 v += 1;
2005 }
2006
Ben Vanik1fd3b282017-07-10 14:08:12 -07002007 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002008 }
2009
Ben Vanik1fd3b282017-07-10 14:08:12 -07002010 bool Program::applyUniform2bv(Device *device, GLint location, GLsizei count, const GLboolean *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002011 {
2012 int vector[MAX_UNIFORM_VECTORS][4];
2013
2014 for(int i = 0; i < count; i++)
2015 {
2016 vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2017 vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2018 vector[i][2] = 0;
2019 vector[i][3] = 0;
2020
2021 v += 2;
2022 }
2023
Ben Vanik1fd3b282017-07-10 14:08:12 -07002024 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002025 }
2026
Ben Vanik1fd3b282017-07-10 14:08:12 -07002027 bool Program::applyUniform3bv(Device *device, GLint location, GLsizei count, const GLboolean *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002028 {
2029 int vector[MAX_UNIFORM_VECTORS][4];
2030
2031 for(int i = 0; i < count; i++)
2032 {
2033 vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2034 vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2035 vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2036 vector[i][3] = 0;
2037
2038 v += 3;
2039 }
2040
Ben Vanik1fd3b282017-07-10 14:08:12 -07002041 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002042 }
2043
Ben Vanik1fd3b282017-07-10 14:08:12 -07002044 bool Program::applyUniform4bv(Device *device, GLint location, GLsizei count, const GLboolean *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002045 {
2046 int vector[MAX_UNIFORM_VECTORS][4];
2047
2048 for(int i = 0; i < count; i++)
2049 {
2050 vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2051 vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2052 vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2053 vector[i][3] = (v[3] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2054
2055 v += 4;
2056 }
2057
Ben Vanik1fd3b282017-07-10 14:08:12 -07002058 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002059 }
2060
Ben Vanik1fd3b282017-07-10 14:08:12 -07002061 bool Program::applyUniform1fv(Device *device, GLint location, GLsizei count, const GLfloat *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002062 {
2063 float vector[MAX_UNIFORM_VECTORS][4];
2064
2065 for(int i = 0; i < count; i++)
2066 {
2067 vector[i][0] = v[0];
2068 vector[i][1] = 0;
2069 vector[i][2] = 0;
2070 vector[i][3] = 0;
2071
2072 v += 1;
2073 }
2074
Ben Vanik1fd3b282017-07-10 14:08:12 -07002075 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002076 }
2077
Ben Vanik1fd3b282017-07-10 14:08:12 -07002078 bool Program::applyUniform2fv(Device *device, GLint location, GLsizei count, const GLfloat *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002079 {
2080 float vector[MAX_UNIFORM_VECTORS][4];
2081
2082 for(int i = 0; i < count; i++)
2083 {
2084 vector[i][0] = v[0];
2085 vector[i][1] = v[1];
2086 vector[i][2] = 0;
2087 vector[i][3] = 0;
2088
2089 v += 2;
2090 }
2091
Ben Vanik1fd3b282017-07-10 14:08:12 -07002092 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002093 }
2094
Ben Vanik1fd3b282017-07-10 14:08:12 -07002095 bool Program::applyUniform3fv(Device *device, GLint location, GLsizei count, const GLfloat *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002096 {
2097 float vector[MAX_UNIFORM_VECTORS][4];
2098
2099 for(int i = 0; i < count; i++)
2100 {
2101 vector[i][0] = v[0];
2102 vector[i][1] = v[1];
2103 vector[i][2] = v[2];
2104 vector[i][3] = 0;
2105
2106 v += 3;
2107 }
2108
Ben Vanik1fd3b282017-07-10 14:08:12 -07002109 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002110 }
2111
Ben Vanik1fd3b282017-07-10 14:08:12 -07002112 bool Program::applyUniform4fv(Device *device, GLint location, GLsizei count, const GLfloat *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002113 {
Ben Vanik1fd3b282017-07-10 14:08:12 -07002114 return applyUniform(device, location, (float*)v);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002115 }
2116
Ben Vanik1fd3b282017-07-10 14:08:12 -07002117 bool Program::applyUniformMatrix2fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002118 {
2119 float matrix[(MAX_UNIFORM_VECTORS + 1) / 2][2][4];
2120
2121 for(int i = 0; i < count; i++)
2122 {
2123 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = 0; matrix[i][0][3] = 0;
2124 matrix[i][1][0] = value[2]; matrix[i][1][1] = value[3]; matrix[i][1][2] = 0; matrix[i][1][3] = 0;
2125
2126 value += 4;
2127 }
2128
Ben Vanik1fd3b282017-07-10 14:08:12 -07002129 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002130 }
2131
Ben Vanik1fd3b282017-07-10 14:08:12 -07002132 bool Program::applyUniformMatrix2x3fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002133 {
2134 float matrix[(MAX_UNIFORM_VECTORS + 1) / 2][2][4];
2135
2136 for(int i = 0; i < count; i++)
2137 {
2138 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = value[2]; matrix[i][0][3] = 0;
2139 matrix[i][1][0] = value[3]; matrix[i][1][1] = value[4]; matrix[i][1][2] = value[5]; matrix[i][1][3] = 0;
2140
2141 value += 6;
2142 }
2143
Ben Vanik1fd3b282017-07-10 14:08:12 -07002144 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002145 }
2146
Ben Vanik1fd3b282017-07-10 14:08:12 -07002147 bool Program::applyUniformMatrix2x4fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002148 {
2149 float matrix[(MAX_UNIFORM_VECTORS + 1) / 2][2][4];
2150
2151 for(int i = 0; i < count; i++)
2152 {
2153 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = value[2]; matrix[i][0][3] = value[3];
2154 matrix[i][1][0] = value[4]; matrix[i][1][1] = value[5]; matrix[i][1][2] = value[6]; matrix[i][1][3] = value[7];
2155
2156 value += 8;
2157 }
2158
Ben Vanik1fd3b282017-07-10 14:08:12 -07002159 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002160 }
2161
Ben Vanik1fd3b282017-07-10 14:08:12 -07002162 bool Program::applyUniformMatrix3fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002163 {
2164 float matrix[(MAX_UNIFORM_VECTORS + 2) / 3][3][4];
2165
2166 for(int i = 0; i < count; i++)
2167 {
2168 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = value[2]; matrix[i][0][3] = 0;
2169 matrix[i][1][0] = value[3]; matrix[i][1][1] = value[4]; matrix[i][1][2] = value[5]; matrix[i][1][3] = 0;
2170 matrix[i][2][0] = value[6]; matrix[i][2][1] = value[7]; matrix[i][2][2] = value[8]; matrix[i][2][3] = 0;
2171
2172 value += 9;
2173 }
2174
Ben Vanik1fd3b282017-07-10 14:08:12 -07002175 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002176 }
2177
Ben Vanik1fd3b282017-07-10 14:08:12 -07002178 bool Program::applyUniformMatrix3x2fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002179 {
2180 float matrix[(MAX_UNIFORM_VECTORS + 2) / 3][3][4];
2181
2182 for(int i = 0; i < count; i++)
2183 {
2184 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = 0; matrix[i][0][3] = 0;
2185 matrix[i][1][0] = value[2]; matrix[i][1][1] = value[3]; matrix[i][1][2] = 0; matrix[i][1][3] = 0;
2186 matrix[i][2][0] = value[4]; matrix[i][2][1] = value[5]; matrix[i][2][2] = 0; matrix[i][2][3] = 0;
2187
2188 value += 6;
2189 }
2190
Ben Vanik1fd3b282017-07-10 14:08:12 -07002191 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002192 }
2193
Ben Vanik1fd3b282017-07-10 14:08:12 -07002194 bool Program::applyUniformMatrix3x4fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002195 {
2196 float matrix[(MAX_UNIFORM_VECTORS + 2) / 3][3][4];
2197
2198 for(int i = 0; i < count; i++)
2199 {
2200 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = value[2]; matrix[i][0][3] = value[3];
2201 matrix[i][1][0] = value[4]; matrix[i][1][1] = value[5]; matrix[i][1][2] = value[6]; matrix[i][1][3] = value[7];
2202 matrix[i][2][0] = value[8]; matrix[i][2][1] = value[9]; matrix[i][2][2] = value[10]; matrix[i][2][3] = value[11];
2203
2204 value += 12;
2205 }
2206
Ben Vanik1fd3b282017-07-10 14:08:12 -07002207 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002208 }
2209
Ben Vanik1fd3b282017-07-10 14:08:12 -07002210 bool Program::applyUniformMatrix4fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002211 {
Ben Vanik1fd3b282017-07-10 14:08:12 -07002212 return applyUniform(device, location, (float*)value);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002213 }
2214
Ben Vanik1fd3b282017-07-10 14:08:12 -07002215 bool Program::applyUniformMatrix4x2fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002216 {
2217 float matrix[(MAX_UNIFORM_VECTORS + 3) / 4][4][4];
2218
2219 for(int i = 0; i < count; i++)
2220 {
2221 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = 0; matrix[i][0][3] = 0;
2222 matrix[i][1][0] = value[2]; matrix[i][1][1] = value[3]; matrix[i][1][2] = 0; matrix[i][1][3] = 0;
2223 matrix[i][2][0] = value[4]; matrix[i][2][1] = value[5]; matrix[i][2][2] = 0; matrix[i][2][3] = 0;
2224 matrix[i][3][0] = value[6]; matrix[i][3][1] = value[7]; matrix[i][3][2] = 0; matrix[i][3][3] = 0;
2225
2226 value += 8;
2227 }
2228
Ben Vanik1fd3b282017-07-10 14:08:12 -07002229 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002230 }
2231
Ben Vanik1fd3b282017-07-10 14:08:12 -07002232 bool Program::applyUniformMatrix4x3fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002233 {
2234 float matrix[(MAX_UNIFORM_VECTORS + 3) / 4][4][4];
2235
2236 for(int i = 0; i < count; i++)
2237 {
2238 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = value[2]; matrix[i][0][3] = 0;
2239 matrix[i][1][0] = value[3]; matrix[i][1][1] = value[4]; matrix[i][1][2] = value[5]; matrix[i][1][3] = 0;
2240 matrix[i][2][0] = value[6]; matrix[i][2][1] = value[7]; matrix[i][2][2] = value[8]; matrix[i][2][3] = 0;
2241 matrix[i][3][0] = value[9]; matrix[i][3][1] = value[10]; matrix[i][3][2] = value[11]; matrix[i][3][3] = 0;
2242
2243 value += 12;
2244 }
2245
Ben Vanik1fd3b282017-07-10 14:08:12 -07002246 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002247 }
2248
Ben Vanik1fd3b282017-07-10 14:08:12 -07002249 bool Program::applyUniform1iv(Device *device, GLint location, GLsizei count, const GLint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002250 {
2251 GLint vector[MAX_UNIFORM_VECTORS][4];
2252
2253 for(int i = 0; i < count; i++)
2254 {
2255 vector[i][0] = v[i];
2256 vector[i][1] = 0;
2257 vector[i][2] = 0;
2258 vector[i][3] = 0;
2259 }
2260
2261 Uniform *targetUniform = uniforms[uniformIndex[location].index];
2262 if(IsSamplerUniform(targetUniform->type))
2263 {
2264 if(targetUniform->psRegisterIndex != -1)
2265 {
2266 for(int i = 0; i < count; i++)
2267 {
2268 unsigned int samplerIndex = targetUniform->psRegisterIndex + i;
2269
Alexis Hétu2cd00092018-01-03 13:04:09 +00002270 if(samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002271 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002272 ASSERT(samplersPS[samplerIndex].active);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002273 samplersPS[samplerIndex].logicalTextureUnit = v[i];
2274 }
2275 }
2276 }
2277
2278 if(targetUniform->vsRegisterIndex != -1)
2279 {
2280 for(int i = 0; i < count; i++)
2281 {
2282 unsigned int samplerIndex = targetUniform->vsRegisterIndex + i;
2283
Alexis Hétu2cd00092018-01-03 13:04:09 +00002284 if(samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002285 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002286 ASSERT(samplersVS[samplerIndex].active);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002287 samplersVS[samplerIndex].logicalTextureUnit = v[i];
2288 }
2289 }
2290 }
2291 }
2292 else
2293 {
Ben Vanik1fd3b282017-07-10 14:08:12 -07002294 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002295 }
2296
2297 return true;
2298 }
2299
Ben Vanik1fd3b282017-07-10 14:08:12 -07002300 bool Program::applyUniform2iv(Device *device, GLint location, GLsizei count, const GLint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002301 {
2302 GLint vector[MAX_UNIFORM_VECTORS][4];
2303
2304 for(int i = 0; i < count; i++)
2305 {
2306 vector[i][0] = v[0];
2307 vector[i][1] = v[1];
2308 vector[i][2] = 0;
2309 vector[i][3] = 0;
2310
2311 v += 2;
2312 }
2313
Ben Vanik1fd3b282017-07-10 14:08:12 -07002314 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002315 }
2316
Ben Vanik1fd3b282017-07-10 14:08:12 -07002317 bool Program::applyUniform3iv(Device *device, GLint location, GLsizei count, const GLint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002318 {
2319 GLint vector[MAX_UNIFORM_VECTORS][4];
2320
2321 for(int i = 0; i < count; i++)
2322 {
2323 vector[i][0] = v[0];
2324 vector[i][1] = v[1];
2325 vector[i][2] = v[2];
2326 vector[i][3] = 0;
2327
2328 v += 3;
2329 }
2330
Ben Vanik1fd3b282017-07-10 14:08:12 -07002331 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002332 }
2333
Ben Vanik1fd3b282017-07-10 14:08:12 -07002334 bool Program::applyUniform4iv(Device *device, GLint location, GLsizei count, const GLint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002335 {
2336 GLint vector[MAX_UNIFORM_VECTORS][4];
2337
2338 for(int i = 0; i < count; i++)
2339 {
2340 vector[i][0] = v[0];
2341 vector[i][1] = v[1];
2342 vector[i][2] = v[2];
2343 vector[i][3] = v[3];
2344
2345 v += 4;
2346 }
2347
Ben Vanik1fd3b282017-07-10 14:08:12 -07002348 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002349 }
2350
Ben Vanik1fd3b282017-07-10 14:08:12 -07002351 bool Program::applyUniform1uiv(Device *device, GLint location, GLsizei count, const GLuint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002352 {
2353 GLuint vector[MAX_UNIFORM_VECTORS][4];
2354
2355 for(int i = 0; i < count; i++)
2356 {
2357 vector[i][0] = v[i];
2358 vector[i][1] = 0;
2359 vector[i][2] = 0;
2360 vector[i][3] = 0;
2361 }
2362
2363 Uniform *targetUniform = uniforms[uniformIndex[location].index];
2364 if(IsSamplerUniform(targetUniform->type))
2365 {
2366 if(targetUniform->psRegisterIndex != -1)
2367 {
2368 for(int i = 0; i < count; i++)
2369 {
2370 unsigned int samplerIndex = targetUniform->psRegisterIndex + i;
2371
Alexis Hétu2cd00092018-01-03 13:04:09 +00002372 if(samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002373 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002374 ASSERT(samplersPS[samplerIndex].active);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002375 samplersPS[samplerIndex].logicalTextureUnit = v[i];
2376 }
2377 }
2378 }
2379
2380 if(targetUniform->vsRegisterIndex != -1)
2381 {
2382 for(int i = 0; i < count; i++)
2383 {
2384 unsigned int samplerIndex = targetUniform->vsRegisterIndex + i;
2385
Alexis Hétu2cd00092018-01-03 13:04:09 +00002386 if(samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002387 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002388 ASSERT(samplersVS[samplerIndex].active);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002389 samplersVS[samplerIndex].logicalTextureUnit = v[i];
2390 }
2391 }
2392 }
2393 }
2394 else
2395 {
Ben Vanik1fd3b282017-07-10 14:08:12 -07002396 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002397 }
2398
2399 return true;
2400 }
2401
Ben Vanik1fd3b282017-07-10 14:08:12 -07002402 bool Program::applyUniform2uiv(Device *device, GLint location, GLsizei count, const GLuint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002403 {
2404 GLuint vector[MAX_UNIFORM_VECTORS][4];
2405
2406 for(int i = 0; i < count; i++)
2407 {
2408 vector[i][0] = v[0];
2409 vector[i][1] = v[1];
2410 vector[i][2] = 0;
2411 vector[i][3] = 0;
2412
2413 v += 2;
2414 }
2415
Ben Vanik1fd3b282017-07-10 14:08:12 -07002416 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002417 }
2418
Ben Vanik1fd3b282017-07-10 14:08:12 -07002419 bool Program::applyUniform3uiv(Device *device, GLint location, GLsizei count, const GLuint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002420 {
2421 GLuint vector[MAX_UNIFORM_VECTORS][4];
2422
2423 for(int i = 0; i < count; i++)
2424 {
2425 vector[i][0] = v[0];
2426 vector[i][1] = v[1];
2427 vector[i][2] = v[2];
2428 vector[i][3] = 0;
2429
2430 v += 3;
2431 }
2432
Ben Vanik1fd3b282017-07-10 14:08:12 -07002433 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002434 }
2435
Ben Vanik1fd3b282017-07-10 14:08:12 -07002436 bool Program::applyUniform4uiv(Device *device, GLint location, GLsizei count, const GLuint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002437 {
2438 GLuint vector[MAX_UNIFORM_VECTORS][4];
2439
2440 for(int i = 0; i < count; i++)
2441 {
2442 vector[i][0] = v[0];
2443 vector[i][1] = v[1];
2444 vector[i][2] = v[2];
2445 vector[i][3] = v[3];
2446
2447 v += 4;
2448 }
2449
Ben Vanik1fd3b282017-07-10 14:08:12 -07002450 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002451 }
2452
2453 void Program::appendToInfoLog(const char *format, ...)
2454 {
2455 if(!format)
2456 {
2457 return;
2458 }
2459
2460 char info[1024];
2461
2462 va_list vararg;
2463 va_start(vararg, format);
2464 vsnprintf(info, sizeof(info), format, vararg);
2465 va_end(vararg);
2466
2467 size_t infoLength = strlen(info);
2468
2469 if(!infoLog)
2470 {
2471 infoLog = new char[infoLength + 2];
2472 strcpy(infoLog, info);
2473 strcpy(infoLog + infoLength, "\n");
2474 }
2475 else
2476 {
2477 size_t logLength = strlen(infoLog);
2478 char *newLog = new char[logLength + infoLength + 2];
2479 strcpy(newLog, infoLog);
2480 strcpy(newLog + logLength, info);
2481 strcpy(newLog + logLength + infoLength, "\n");
2482
2483 delete[] infoLog;
2484 infoLog = newLog;
2485 }
2486 }
2487
2488 void Program::resetInfoLog()
2489 {
2490 if(infoLog)
2491 {
2492 delete[] infoLog;
2493 infoLog = 0;
2494 }
2495 }
2496
2497 // Returns the program object to an unlinked state, before re-linking, or at destruction
2498 void Program::unlink()
2499 {
2500 delete vertexBinary;
2501 vertexBinary = 0;
2502 delete pixelBinary;
2503 pixelBinary = 0;
2504
Alexis Hetu23f54d72017-12-05 16:03:51 -05002505 linkedAttribute.clear();
2506 linkedAttributeLocation.clear();
2507
Nicolas Capens0bac2852016-05-07 06:09:58 -04002508 for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2509 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04002510 attributeStream[index] = -1;
2511 }
2512
Alexis Hétu2cd00092018-01-03 13:04:09 +00002513 for(int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2514 {
2515 samplersPS[index].active = false;
2516 }
2517
2518 for(int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
2519 {
2520 samplersVS[index].active = false;
2521 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002522
2523 while(!uniforms.empty())
2524 {
2525 delete uniforms.back();
2526 uniforms.pop_back();
2527 }
2528
2529 while(!uniformBlocks.empty())
2530 {
2531 delete uniformBlocks.back();
2532 uniformBlocks.pop_back();
2533 }
2534
2535 uniformIndex.clear();
2536 transformFeedbackLinkedVaryings.clear();
2537
2538 delete[] infoLog;
2539 infoLog = 0;
2540
2541 linked = false;
2542 }
2543
2544 bool Program::isLinked() const
2545 {
2546 return linked;
2547 }
2548
2549 bool Program::isValidated() const
2550 {
2551 return validated;
2552 }
2553
2554 GLint Program::getBinaryLength() const
2555 {
2556 UNIMPLEMENTED();
2557 return 0;
2558 }
2559
2560 void Program::release()
2561 {
2562 referenceCount--;
2563
2564 if(referenceCount == 0 && orphaned)
2565 {
2566 resourceManager->deleteProgram(handle);
2567 }
2568 }
2569
2570 void Program::addRef()
2571 {
2572 referenceCount++;
2573 }
2574
2575 unsigned int Program::getRefCount() const
2576 {
2577 return referenceCount;
2578 }
2579
2580 unsigned int Program::getSerial() const
2581 {
2582 return serial;
2583 }
2584
2585 unsigned int Program::issueSerial()
2586 {
2587 return currentSerial++;
2588 }
2589
2590 size_t Program::getInfoLogLength() const
2591 {
2592 if(!infoLog)
2593 {
2594 return 0;
2595 }
2596 else
2597 {
2598 return strlen(infoLog) + 1;
2599 }
2600 }
2601
2602 void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *buffer)
2603 {
2604 int index = 0;
2605
2606 if(bufSize > 0)
2607 {
2608 if(infoLog)
2609 {
2610 index = std::min(bufSize - 1, (int)strlen(infoLog));
2611 memcpy(buffer, infoLog, index);
2612 }
2613
2614 buffer[index] = '\0';
2615 }
2616
2617 if(length)
2618 {
2619 *length = index;
2620 }
2621 }
2622
2623 void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2624 {
2625 int total = 0;
2626
2627 if(vertexShader && (total < maxCount))
2628 {
2629 shaders[total++] = vertexShader->getName();
2630 }
2631
2632 if(fragmentShader && (total < maxCount))
2633 {
2634 shaders[total++] = fragmentShader->getName();
2635 }
2636
2637 if(count)
2638 {
2639 *count = total;
2640 }
2641 }
2642
2643 void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
2644 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05002645 ASSERT(index < linkedAttribute.size());
Nicolas Capens0bac2852016-05-07 06:09:58 -04002646
Alexis Hetu23f54d72017-12-05 16:03:51 -05002647 std::vector<glsl::Attribute>::const_iterator it = linkedAttribute.begin() + index;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002648
2649 if(bufsize > 0)
2650 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05002651 const char *string = it->name.c_str();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002652
2653 strncpy(name, string, bufsize);
2654 name[bufsize - 1] = '\0';
2655
2656 if(length)
2657 {
Alexis Hetu05c32b92016-06-23 11:32:07 -04002658 *length = static_cast<GLsizei>(strlen(name));
Nicolas Capens0bac2852016-05-07 06:09:58 -04002659 }
2660 }
2661
2662 *size = 1; // Always a single 'type' instance
2663
Alexis Hetu23f54d72017-12-05 16:03:51 -05002664 *type = it->type;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002665 }
2666
2667 size_t Program::getActiveAttributeCount() const
2668 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05002669 return linkedAttribute.size();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002670 }
2671
2672 GLint Program::getActiveAttributeMaxLength() const
2673 {
2674 int maxLength = 0;
2675
Alexis Hetu23f54d72017-12-05 16:03:51 -05002676 std::vector<glsl::Attribute>::const_iterator it = linkedAttribute.begin();
2677 std::vector<glsl::Attribute>::const_iterator itEnd = linkedAttribute.end();
2678 for(; it != itEnd; ++it)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002679 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05002680 maxLength = std::max((int)(it->name.length() + 1), maxLength);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002681 }
2682
2683 return maxLength;
2684 }
2685
2686 void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
2687 {
2688 if(bufsize > 0)
2689 {
2690 std::string string = uniforms[index]->name;
2691
2692 if(uniforms[index]->isArray())
2693 {
2694 string += "[0]";
2695 }
2696
2697 strncpy(name, string.c_str(), bufsize);
2698 name[bufsize - 1] = '\0';
2699
2700 if(length)
2701 {
Alexis Hetu05c32b92016-06-23 11:32:07 -04002702 *length = static_cast<GLsizei>(strlen(name));
Nicolas Capens0bac2852016-05-07 06:09:58 -04002703 }
2704 }
2705
2706 *size = uniforms[index]->size();
2707
2708 *type = uniforms[index]->type;
2709 }
2710
2711 size_t Program::getActiveUniformCount() const
2712 {
2713 return uniforms.size();
2714 }
2715
2716 GLint Program::getActiveUniformMaxLength() const
2717 {
2718 int maxLength = 0;
2719
2720 size_t numUniforms = uniforms.size();
2721 for(size_t uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2722 {
2723 if(!uniforms[uniformIndex]->name.empty())
2724 {
2725 int length = (int)(uniforms[uniformIndex]->name.length() + 1);
2726 if(uniforms[uniformIndex]->isArray())
2727 {
2728 length += 3; // Counting in "[0]".
2729 }
2730 maxLength = std::max(length, maxLength);
2731 }
2732 }
2733
2734 return maxLength;
2735 }
2736
2737 GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
2738 {
2739 const Uniform& uniform = *uniforms[index];
2740 switch(pname)
2741 {
2742 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2743 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.size());
2744 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
2745 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockInfo.index;
2746 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2747 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2748 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2749 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
2750 default:
2751 UNREACHABLE(pname);
2752 break;
2753 }
2754 return 0;
2755 }
2756
2757 void Program::getActiveUniformBlockName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const
2758 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002759 if(index >= getActiveUniformBlockCount())
2760 {
2761 return error(GL_INVALID_VALUE);
2762 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002763
2764 const UniformBlock &uniformBlock = *uniformBlocks[index];
2765
2766 if(bufSize > 0)
2767 {
2768 std::string string = uniformBlock.name;
2769
2770 if(uniformBlock.isArrayElement())
2771 {
2772 std::ostringstream elementIndex;
2773 elementIndex << uniformBlock.elementIndex;
2774 string += "[" + elementIndex.str() + "]";
2775 }
2776
2777 strncpy(name, string.c_str(), bufSize);
2778 name[bufSize - 1] = '\0';
2779
2780 if(length)
2781 {
Alexis Hetu05c32b92016-06-23 11:32:07 -04002782 *length = static_cast<GLsizei>(strlen(name));
Nicolas Capens0bac2852016-05-07 06:09:58 -04002783 }
2784 }
2785 }
2786
2787 size_t Program::getActiveUniformBlockCount() const
2788 {
2789 return uniformBlocks.size();
2790 }
2791
2792 GLint Program::getActiveUniformBlockMaxLength() const
2793 {
Alexis Hetu05c32b92016-06-23 11:32:07 -04002794 GLint maxLength = 0;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002795
2796 if(isLinked())
2797 {
2798 size_t numUniformBlocks = getActiveUniformBlockCount();
2799 for(size_t uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2800 {
2801 const UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];
2802 if(!uniformBlock.name.empty())
2803 {
Alexis Hetu05c32b92016-06-23 11:32:07 -04002804 GLint length = static_cast<GLint>(uniformBlock.name.length() + 1);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002805
2806 // Counting in "[0]".
Alexis Hetu05c32b92016-06-23 11:32:07 -04002807 const GLint arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002808
2809 maxLength = std::max(length + arrayLength, maxLength);
2810 }
2811 }
2812 }
2813
2814 return maxLength;
2815 }
2816
2817 void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
2818 {
2819 transformFeedbackVaryings.resize(count);
2820 for(GLsizei i = 0; i < count; i++)
2821 {
2822 transformFeedbackVaryings[i] = varyings[i];
2823 }
2824
2825 transformFeedbackBufferMode = bufferMode;
2826 }
2827
2828 void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
2829 {
2830 if(linked)
2831 {
2832 ASSERT(index < transformFeedbackLinkedVaryings.size());
2833 const LinkedVarying &varying = transformFeedbackLinkedVaryings[index];
2834 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
2835 if(length)
2836 {
2837 *length = lastNameIdx;
2838 }
2839 if(size)
2840 {
2841 *size = varying.size;
2842 }
2843 if(type)
2844 {
2845 *type = varying.type;
2846 }
2847 if(name)
2848 {
2849 memcpy(name, varying.name.c_str(), lastNameIdx);
2850 name[lastNameIdx] = '\0';
2851 }
2852 }
2853 }
2854
2855 GLsizei Program::getTransformFeedbackVaryingCount() const
2856 {
2857 if(linked)
2858 {
2859 return static_cast<GLsizei>(transformFeedbackLinkedVaryings.size());
2860 }
2861 else
2862 {
2863 return 0;
2864 }
2865 }
2866
2867 GLsizei Program::getTransformFeedbackVaryingMaxLength() const
2868 {
2869 if(linked)
2870 {
2871 GLsizei maxSize = 0;
2872 for(size_t i = 0; i < transformFeedbackLinkedVaryings.size(); i++)
2873 {
2874 const LinkedVarying &varying = transformFeedbackLinkedVaryings[i];
2875 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
2876 }
2877
2878 return maxSize;
2879 }
2880 else
2881 {
2882 return 0;
2883 }
2884 }
2885
2886 GLenum Program::getTransformFeedbackBufferMode() const
2887 {
2888 return transformFeedbackBufferMode;
2889 }
2890
2891 void Program::flagForDeletion()
2892 {
2893 orphaned = true;
2894 }
2895
2896 bool Program::isFlaggedForDeletion() const
2897 {
2898 return orphaned;
2899 }
2900
Ben Vanik1fd3b282017-07-10 14:08:12 -07002901 void Program::validate(Device* device)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002902 {
2903 resetInfoLog();
2904
2905 if(!isLinked())
2906 {
2907 appendToInfoLog("Program has not been successfully linked.");
2908 validated = false;
2909 }
2910 else
2911 {
Ben Vanik1fd3b282017-07-10 14:08:12 -07002912 applyUniforms(device);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002913 if(!validateSamplers(true))
2914 {
2915 validated = false;
2916 }
2917 else
2918 {
2919 validated = true;
2920 }
2921 }
2922 }
2923
2924 bool Program::validateSamplers(bool logErrors)
2925 {
2926 // if any two active samplers in a program are of different types, but refer to the same
2927 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2928 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2929
2930 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
2931
2932 for(unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS; i++)
2933 {
2934 textureUnitType[i] = TEXTURE_UNKNOWN;
2935 }
2936
Alexis Hétu2cd00092018-01-03 13:04:09 +00002937 for(unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002938 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002939 if(samplersPS[i].active)
Alexis Hetua141a072017-12-20 14:49:37 -05002940 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002941 unsigned int unit = samplersPS[i].logicalTextureUnit;
Alexis Hetua141a072017-12-20 14:49:37 -05002942
Alexis Hétu2cd00092018-01-03 13:04:09 +00002943 if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002944 {
2945 if(logErrors)
2946 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002947 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002948 }
2949
2950 return false;
2951 }
Alexis Hétu2cd00092018-01-03 13:04:09 +00002952
2953 if(textureUnitType[unit] != TEXTURE_UNKNOWN)
2954 {
2955 if(samplersPS[i].textureType != textureUnitType[unit])
2956 {
2957 if(logErrors)
2958 {
2959 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2960 }
2961
2962 return false;
2963 }
2964 }
2965 else
2966 {
2967 textureUnitType[unit] = samplersPS[i].textureType;
2968 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002969 }
2970 }
2971
Alexis Hétu2cd00092018-01-03 13:04:09 +00002972 for(unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002973 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002974 if(samplersVS[i].active)
Alexis Hetua141a072017-12-20 14:49:37 -05002975 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002976 unsigned int unit = samplersVS[i].logicalTextureUnit;
Alexis Hetua141a072017-12-20 14:49:37 -05002977
Alexis Hétu2cd00092018-01-03 13:04:09 +00002978 if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002979 {
2980 if(logErrors)
2981 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002982 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002983 }
2984
2985 return false;
2986 }
Alexis Hétu2cd00092018-01-03 13:04:09 +00002987
2988 if(textureUnitType[unit] != TEXTURE_UNKNOWN)
2989 {
2990 if(samplersVS[i].textureType != textureUnitType[unit])
2991 {
2992 if(logErrors)
2993 {
2994 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
2995 }
2996
2997 return false;
2998 }
2999 }
3000 else
3001 {
3002 textureUnitType[unit] = samplersVS[i].textureType;
3003 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003004 }
3005 }
3006
3007 return true;
3008 }
3009}