blob: dc64813a289f5d4b3a93d5e6dac38512814af57f [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 }
Nicolas Capens0bac2852016-05-07 06:09:58 -040054 }
55
Alexis Hetu924513c2018-01-05 15:48:12 -050056 Uniform::Uniform(const glsl::Uniform &uniform, const BlockInfo &blockInfo)
57 : type(uniform.type), precision(uniform.precision), name(uniform.name),
58 arraySize(uniform.arraySize), blockInfo(blockInfo), fields(uniform.fields)
Nicolas Capens0bac2852016-05-07 06:09:58 -040059 {
Alexis Hetu924513c2018-01-05 15:48:12 -050060 if((blockInfo.index == -1) && uniform.fields.empty())
Nicolas Capens0bac2852016-05-07 06:09:58 -040061 {
62 size_t bytes = UniformTypeSize(type) * size();
63 data = new unsigned char[bytes];
64 memset(data, 0, bytes);
65 }
Nicolas Capens0bac2852016-05-07 06:09:58 -040066 }
67
68 Uniform::~Uniform()
69 {
70 delete[] data;
71 }
72
73 bool Uniform::isArray() const
74 {
75 return arraySize >= 1;
76 }
77
78 int Uniform::size() const
79 {
80 return arraySize > 0 ? arraySize : 1;
81 }
82
83 int Uniform::registerCount() const
84 {
85 return size() * VariableRegisterCount(type);
86 }
87
88 UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize, std::vector<unsigned int> memberUniformIndexes) :
89 name(name), elementIndex(elementIndex), dataSize(dataSize), memberUniformIndexes(memberUniformIndexes), psRegisterIndex(GL_INVALID_INDEX), vsRegisterIndex(GL_INVALID_INDEX)
90 {
91 }
92
93 void UniformBlock::setRegisterIndex(GLenum shader, unsigned int registerIndex)
94 {
95 switch(shader)
96 {
97 case GL_VERTEX_SHADER:
98 vsRegisterIndex = registerIndex;
99 break;
100 case GL_FRAGMENT_SHADER:
101 psRegisterIndex = registerIndex;
102 break;
103 default:
104 UNREACHABLE(shader);
105 }
106 }
107
108 bool UniformBlock::isArrayElement() const
109 {
110 return elementIndex != GL_INVALID_INDEX;
111 }
112
113 bool UniformBlock::isReferencedByVertexShader() const
114 {
115 return vsRegisterIndex != GL_INVALID_INDEX;
116 }
117
118 bool UniformBlock::isReferencedByFragmentShader() const
119 {
120 return psRegisterIndex != GL_INVALID_INDEX;
121 }
122
123 UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index) : name(name), element(element), index(index)
124 {
125 }
126
127 LinkedVarying::LinkedVarying()
128 {
129 }
130
131 LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, int reg, int col)
132 : name(name), type(type), size(size), reg(reg), col(col)
133 {
134 }
135
136 Program::Program(ResourceManager *manager, GLuint handle) : serial(issueSerial()), resourceManager(manager), handle(handle)
137 {
Nicolas Capens0bac2852016-05-07 06:09:58 -0400138 fragmentShader = 0;
139 vertexShader = 0;
140 pixelBinary = 0;
141 vertexBinary = 0;
142
143 transformFeedbackBufferMode = GL_INTERLEAVED_ATTRIBS;
144 totalLinkedVaryingsComponents = 0;
145
146 infoLog = 0;
147 validated = false;
148
149 resetUniformBlockBindings();
150 unlink();
151
152 orphaned = false;
153 retrievableBinary = false;
154 referenceCount = 0;
155 }
156
157 Program::~Program()
158 {
159 unlink();
160
161 if(vertexShader)
162 {
163 vertexShader->release();
164 }
165
166 if(fragmentShader)
167 {
168 fragmentShader->release();
169 }
170 }
171
172 bool Program::attachShader(Shader *shader)
173 {
174 if(shader->getType() == GL_VERTEX_SHADER)
175 {
176 if(vertexShader)
177 {
178 return false;
179 }
180
181 vertexShader = (VertexShader*)shader;
182 vertexShader->addRef();
183 }
184 else if(shader->getType() == GL_FRAGMENT_SHADER)
185 {
186 if(fragmentShader)
187 {
188 return false;
189 }
190
191 fragmentShader = (FragmentShader*)shader;
192 fragmentShader->addRef();
193 }
194 else UNREACHABLE(shader->getType());
195
196 return true;
197 }
198
199 bool Program::detachShader(Shader *shader)
200 {
201 if(shader->getType() == GL_VERTEX_SHADER)
202 {
203 if(vertexShader != shader)
204 {
205 return false;
206 }
207
208 vertexShader->release();
209 vertexShader = 0;
210 }
211 else if(shader->getType() == GL_FRAGMENT_SHADER)
212 {
213 if(fragmentShader != shader)
214 {
215 return false;
216 }
217
218 fragmentShader->release();
219 fragmentShader = 0;
220 }
221 else UNREACHABLE(shader->getType());
222
223 return true;
224 }
225
226 int Program::getAttachedShadersCount() const
227 {
228 return (vertexShader ? 1 : 0) + (fragmentShader ? 1 : 0);
229 }
230
231 sw::PixelShader *Program::getPixelShader()
232 {
233 return pixelBinary;
234 }
235
236 sw::VertexShader *Program::getVertexShader()
237 {
238 return vertexBinary;
239 }
240
Alexis Hetub3f5ed72017-08-16 16:37:19 -0400241 GLint Program::getFragDataLocation(const GLchar *name)
242 {
243 if(name && linked)
244 {
245 std::string baseName(name);
246 unsigned int subscript = GL_INVALID_INDEX;
247 baseName = ParseUniformName(baseName, &subscript);
Nicolas Capens88e7dcf2018-01-11 14:46:12 -0500248 for(auto const &varying : fragmentShader->varyings)
Alexis Hetub3f5ed72017-08-16 16:37:19 -0400249 {
Nicolas Capens88e7dcf2018-01-11 14:46:12 -0500250 if(varying.qualifier == EvqFragmentOut)
Alexis Hetub3f5ed72017-08-16 16:37:19 -0400251 {
Nicolas Capens88e7dcf2018-01-11 14:46:12 -0500252 if(varying.name == baseName)
253 {
254 ASSERT(varying.registerIndex >= 0);
255
256 if(subscript == GL_INVALID_INDEX) // No subscript
257 {
258 return varying.registerIndex;
259 }
260
261 int rowCount = VariableRowCount(varying.type);
262 int colCount = VariableColumnCount(varying.type);
263
264 return varying.registerIndex + (rowCount > 1 ? colCount * subscript : subscript);
265 }
Alexis Hetub3f5ed72017-08-16 16:37:19 -0400266 }
267 }
268 }
269
270 return -1;
271 }
272
Nicolas Capens0bac2852016-05-07 06:09:58 -0400273 void Program::bindAttributeLocation(GLuint index, const char *name)
274 {
Alexis Hetu23f54d72017-12-05 16:03:51 -0500275 attributeBinding[name] = index;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400276 }
277
Alexis Hetu05c32b92016-06-23 11:32:07 -0400278 GLint Program::getAttributeLocation(const char *name)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400279 {
Nicolas Capens378c4342018-08-07 23:57:21 -0400280 return name ? getAttributeLocation(std::string(name)) : -1;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400281 }
282
283 int Program::getAttributeStream(int attributeIndex)
284 {
285 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
286
287 return attributeStream[attributeIndex];
288 }
289
Alexis Hétu2cd00092018-01-03 13:04:09 +0000290 // 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)
291 GLint Program::getSamplerMapping(sw::SamplerType type, unsigned int samplerIndex)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400292 {
Alexis Hétu2cd00092018-01-03 13:04:09 +0000293 GLint logicalTextureUnit = -1;
294
295 switch(type)
296 {
297 case sw::SAMPLER_PIXEL:
298 ASSERT(samplerIndex < sizeof(samplersPS) / sizeof(samplersPS[0]));
299
300 if(samplersPS[samplerIndex].active)
301 {
302 logicalTextureUnit = samplersPS[samplerIndex].logicalTextureUnit;
303 }
304 break;
305 case sw::SAMPLER_VERTEX:
306 ASSERT(samplerIndex < sizeof(samplersVS) / sizeof(samplersVS[0]));
307
308 if(samplersVS[samplerIndex].active)
309 {
310 logicalTextureUnit = samplersVS[samplerIndex].logicalTextureUnit;
311 }
312 break;
313 default: UNREACHABLE(type);
314 }
315
316 if(logicalTextureUnit < MAX_COMBINED_TEXTURE_IMAGE_UNITS)
317 {
318 return logicalTextureUnit;
319 }
320
321 return -1;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400322 }
323
324 // Returns the texture type for a given sampler type and index (0-15 for the pixel shader and 0-3 for the vertex shader)
325 TextureType Program::getSamplerTextureType(sw::SamplerType type, unsigned int samplerIndex)
326 {
327 switch(type)
328 {
329 case sw::SAMPLER_PIXEL:
Alexis Hétu2cd00092018-01-03 13:04:09 +0000330 ASSERT(samplerIndex < sizeof(samplersPS)/sizeof(samplersPS[0]));
331 ASSERT(samplersPS[samplerIndex].active);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400332 return samplersPS[samplerIndex].textureType;
333 case sw::SAMPLER_VERTEX:
Alexis Hétu2cd00092018-01-03 13:04:09 +0000334 ASSERT(samplerIndex < sizeof(samplersVS)/sizeof(samplersVS[0]));
335 ASSERT(samplersVS[samplerIndex].active);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400336 return samplersVS[samplerIndex].textureType;
337 default: UNREACHABLE(type);
338 }
339
340 return TEXTURE_2D;
341 }
342
Nicolas Capens0d8993c2018-07-16 11:13:49 -0400343 Uniform *Program::getUniform(const std::string &name) const
Alexis Hetuec5da192017-10-06 13:23:49 -0400344 {
345 unsigned int subscript = GL_INVALID_INDEX;
346 std::string baseName = es2::ParseUniformName(name, &subscript);
347
Nicolas Capens0d8993c2018-07-16 11:13:49 -0400348 for(size_t index = 0; index < uniforms.size(); index++)
Alexis Hetuec5da192017-10-06 13:23:49 -0400349 {
Nicolas Capens0d8993c2018-07-16 11:13:49 -0400350 if(uniforms[index]->name == baseName)
Alexis Hetuec5da192017-10-06 13:23:49 -0400351 {
Nicolas Capens0d8993c2018-07-16 11:13:49 -0400352 return uniforms[index];
Alexis Hetuec5da192017-10-06 13:23:49 -0400353 }
354 }
355
Nicolas Capens0d8993c2018-07-16 11:13:49 -0400356 return nullptr;
Alexis Hetuec5da192017-10-06 13:23:49 -0400357 }
358
Nicolas Capens0bac2852016-05-07 06:09:58 -0400359 GLint Program::getUniformLocation(const std::string &name) const
360 {
Alexis Hetu53977f12016-06-27 16:04:31 -0400361 unsigned int subscript = GL_INVALID_INDEX;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400362 std::string baseName = es2::ParseUniformName(name, &subscript);
363
Nicolas Capens0d8993c2018-07-16 11:13:49 -0400364 for(size_t location = 0; location < uniformIndex.size(); location++)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400365 {
Nicolas Capens0d8993c2018-07-16 11:13:49 -0400366 if(uniformIndex[location].name == baseName)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400367 {
Nicolas Capens0d8993c2018-07-16 11:13:49 -0400368 const unsigned int index = uniformIndex[location].index;
369
370 if(index != GL_INVALID_INDEX)
371 {
372 if(subscript == GL_INVALID_INDEX)
373 {
374 return (GLint)location;
375 }
376 else if(uniforms[index]->isArray())
377 {
378 if(uniformIndex[location].element == subscript)
379 {
380 return (GLint)location;
381 }
382 }
383 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400384 }
385 }
386
387 return -1;
388 }
389
390 GLuint Program::getUniformIndex(const std::string &name) const
391 {
Alexis Hetu53977f12016-06-27 16:04:31 -0400392 unsigned int subscript = GL_INVALID_INDEX;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400393 std::string baseName = es2::ParseUniformName(name, &subscript);
394
395 // The app is not allowed to specify array indices other than 0 for arrays of basic types
396 if(subscript != 0 && subscript != GL_INVALID_INDEX)
397 {
398 return GL_INVALID_INDEX;
399 }
400
401 size_t numUniforms = uniforms.size();
402 for(GLuint index = 0; index < numUniforms; index++)
403 {
404 if(uniforms[index]->name == baseName)
405 {
406 if(uniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
407 {
408 return index;
409 }
410 }
411 }
412
413 return GL_INVALID_INDEX;
414 }
415
416 void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
417 {
418 ASSERT(uniformBlockIndex < getActiveUniformBlockCount());
419
420 const UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];
421
422 switch(pname)
423 {
424 case GL_UNIFORM_BLOCK_DATA_SIZE:
425 *params = static_cast<GLint>(uniformBlock.dataSize);
426 break;
427 case GL_UNIFORM_BLOCK_NAME_LENGTH:
428 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
429 break;
430 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
431 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
432 break;
433 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
434 {
435 for(unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
436 {
437 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
438 }
439 }
440 break;
441 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
442 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
443 break;
444 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
445 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
446 break;
447 default: UNREACHABLE(pname);
448 }
449 }
450
451 GLuint Program::getUniformBlockIndex(const std::string &name) const
452 {
Alexis Hetu53977f12016-06-27 16:04:31 -0400453 unsigned int subscript = GL_INVALID_INDEX;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400454 std::string baseName = es2::ParseUniformName(name, &subscript);
455
456 size_t numUniformBlocks = getActiveUniformBlockCount();
457 for(GLuint blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
458 {
459 const UniformBlock &uniformBlock = *uniformBlocks[blockIndex];
460 if(uniformBlock.name == baseName)
461 {
462 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
463 if(subscript == uniformBlock.elementIndex || arrayElementZero)
464 {
465 return blockIndex;
466 }
467 }
468 }
469
470 return GL_INVALID_INDEX;
471 }
472
473 void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
474 {
Nicolas Capens7f1c3d02018-07-30 16:42:49 -0400475 ASSERT(uniformBlockIndex < getActiveUniformBlockCount());
Alexis Hetu3eb573f2017-11-22 13:27:03 -0500476
Nicolas Capens0bac2852016-05-07 06:09:58 -0400477 uniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
478 }
479
480 GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
481 {
Nicolas Capens7f1c3d02018-07-30 16:42:49 -0400482 ASSERT(uniformBlockIndex < getActiveUniformBlockCount());
483
Nicolas Capens0bac2852016-05-07 06:09:58 -0400484 return uniformBlockBindings[uniformBlockIndex];
485 }
486
487 void Program::resetUniformBlockBindings()
488 {
489 for(unsigned int blockId = 0; blockId < MAX_UNIFORM_BUFFER_BINDINGS; blockId++)
490 {
491 uniformBlockBindings[blockId] = 0;
492 }
493 }
494
495 bool Program::setUniformfv(GLint location, GLsizei count, const GLfloat *v, int numElements)
496 {
497 ASSERT(numElements >= 1 && numElements <= 4);
498
499 static GLenum floatType[] = { GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4 };
500 static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };
501
Alexis Hetuec5da192017-10-06 13:23:49 -0400502 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400503 {
504 return false;
505 }
506
507 Uniform *targetUniform = uniforms[uniformIndex[location].index];
508 targetUniform->dirty = true;
509
510 int size = targetUniform->size();
511
512 if(size == 1 && count > 1)
513 {
514 return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
515 }
516
517 count = std::min(size - (int)uniformIndex[location].element, count);
518
519 int index = numElements - 1;
520 if(targetUniform->type == floatType[index])
521 {
522 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat)* numElements,
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800523 v, numElements * sizeof(GLfloat) * count);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400524 }
525 else if(targetUniform->type == boolType[index])
526 {
527 GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * numElements;
528
529 for(int i = 0; i < count * numElements; i++)
530 {
531 boolParams[i] = (v[i] == 0.0f) ? GL_FALSE : GL_TRUE;
532 }
533 }
534 else
535 {
536 return false;
537 }
538
539 return true;
540 }
541
542 bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
543 {
544 return setUniformfv(location, count, v, 1);
545 }
546
547 bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
548 {
549 return setUniformfv(location, count, v, 2);
550 }
551
552 bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
553 {
554 return setUniformfv(location, count, v, 3);
555 }
556
557 bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
558 {
559 return setUniformfv(location, count, v, 4);
560 }
561
562 bool Program::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum type)
563 {
564 int numElements;
565 switch(type)
566 {
567 case GL_FLOAT_MAT2:
568 numElements = 4;
569 break;
570 case GL_FLOAT_MAT2x3:
571 case GL_FLOAT_MAT3x2:
572 numElements = 6;
573 break;
574 case GL_FLOAT_MAT2x4:
575 case GL_FLOAT_MAT4x2:
576 numElements = 8;
577 break;
578 case GL_FLOAT_MAT3:
579 numElements = 9;
580 break;
581 case GL_FLOAT_MAT3x4:
582 case GL_FLOAT_MAT4x3:
583 numElements = 12;
584 break;
585 case GL_FLOAT_MAT4:
586 numElements = 16;
587 break;
588 default:
589 return false;
590 }
591
Alexis Hetuec5da192017-10-06 13:23:49 -0400592 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400593 {
594 return false;
595 }
596
597 Uniform *targetUniform = uniforms[uniformIndex[location].index];
598 targetUniform->dirty = true;
599
600 if(targetUniform->type != type)
601 {
602 return false;
603 }
604
605 int size = targetUniform->size();
606
607 if(size == 1 && count > 1)
608 {
609 return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
610 }
611
612 count = std::min(size - (int)uniformIndex[location].element, count);
613
614 GLfloat* dst = reinterpret_cast<GLfloat*>(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * numElements);
615
616 if(transpose == GL_FALSE)
617 {
618 memcpy(dst, value, numElements * sizeof(GLfloat) * count);
619 }
620 else
621 {
622 const int rowSize = VariableRowCount(type);
623 const int colSize = VariableColumnCount(type);
624 for(int n = 0; n < count; ++n)
625 {
626 for(int i = 0; i < colSize; ++i)
627 {
628 for(int j = 0; j < rowSize; ++j)
629 {
630 dst[i * rowSize + j] = value[j * colSize + i];
631 }
632 }
633 dst += numElements;
634 value += numElements;
635 }
636 }
637
638
639 return true;
640 }
641
642 bool Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
643 {
644 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT2);
645 }
646
647 bool Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
648 {
649 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT2x3);
650 }
651
652 bool Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
653 {
654 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT2x4);
655 }
656
657 bool Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
658 {
659 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT3);
660 }
661
662 bool Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
663 {
664 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT3x2);
665 }
666
667 bool Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
668 {
669 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT3x4);
670 }
671
672 bool Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
673 {
674 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT4);
675 }
676
677 bool Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
678 {
679 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT4x2);
680 }
681
682 bool Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
683 {
684 return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT4x3);
685 }
686
687 bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
688 {
Alexis Hetuec5da192017-10-06 13:23:49 -0400689 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400690 {
691 return false;
692 }
693
694 Uniform *targetUniform = uniforms[uniformIndex[location].index];
695 targetUniform->dirty = true;
696
697 int size = targetUniform->size();
698
699 if(size == 1 && count > 1)
700 {
701 return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
702 }
703
704 count = std::min(size - (int)uniformIndex[location].element, count);
705
Alexis Hetu3eb573f2017-11-22 13:27:03 -0500706 if(targetUniform->type == GL_INT || IsSamplerUniform(targetUniform->type))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400707 {
708 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint),
709 v, sizeof(GLint) * count);
710 }
711 else if(targetUniform->type == GL_BOOL)
712 {
713 GLboolean *boolParams = new GLboolean[count];
714
715 for(int i = 0; i < count; i++)
716 {
717 if(v[i] == 0)
718 {
719 boolParams[i] = GL_FALSE;
720 }
721 else
722 {
723 boolParams[i] = GL_TRUE;
724 }
725 }
726
727 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean),
728 boolParams, sizeof(GLboolean) * count);
729
730 delete[] boolParams;
731 }
732 else
733 {
734 return false;
735 }
736
737 return true;
738 }
739
740 bool Program::setUniformiv(GLint location, GLsizei count, const GLint *v, int numElements)
741 {
742 static GLenum intType[] = { GL_INT, GL_INT_VEC2, GL_INT_VEC3, GL_INT_VEC4 };
Nicolas Capens0bac2852016-05-07 06:09:58 -0400743 static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };
744
Alexis Hetuec5da192017-10-06 13:23:49 -0400745 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400746 {
747 return false;
748 }
749
750 Uniform *targetUniform = uniforms[uniformIndex[location].index];
751 targetUniform->dirty = true;
752
753 int size = targetUniform->size();
754
755 if(size == 1 && count > 1)
756 {
757 return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
758 }
759
760 count = std::min(size - (int)uniformIndex[location].element, count);
761
762 int index = numElements - 1;
Alexis Hetu3eb573f2017-11-22 13:27:03 -0500763 if(targetUniform->type == intType[index])
Nicolas Capens0bac2852016-05-07 06:09:58 -0400764 {
765 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint)* numElements,
766 v, numElements * sizeof(GLint)* count);
767 }
768 else if(targetUniform->type == boolType[index])
769 {
770 GLboolean *boolParams = new GLboolean[count * numElements];
771
772 for(int i = 0; i < count * numElements; i++)
773 {
774 boolParams[i] = (v[i] == 0) ? GL_FALSE : GL_TRUE;
775 }
776
777 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean)* numElements,
778 boolParams, numElements * sizeof(GLboolean)* count);
779
780 delete[] boolParams;
781 }
782 else
783 {
784 return false;
785 }
786
787 return true;
788 }
789
790 bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
791 {
792 return setUniformiv(location, count, v, 2);
793 }
794
795 bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
796 {
797 return setUniformiv(location, count, v, 3);
798 }
799
800 bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
801 {
802 return setUniformiv(location, count, v, 4);
803 }
804
805 bool Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
806 {
Alexis Hetuec5da192017-10-06 13:23:49 -0400807 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400808 {
809 return false;
810 }
811
812 Uniform *targetUniform = uniforms[uniformIndex[location].index];
813 targetUniform->dirty = true;
814
815 int size = targetUniform->size();
816
817 if(size == 1 && count > 1)
818 {
819 return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
820 }
821
822 count = std::min(size - (int)uniformIndex[location].element, count);
823
Alexis Hetu3eb573f2017-11-22 13:27:03 -0500824 if(targetUniform->type == GL_UNSIGNED_INT)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400825 {
826 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLuint),
827 v, sizeof(GLuint)* count);
828 }
829 else if(targetUniform->type == GL_BOOL)
830 {
831 GLboolean *boolParams = new GLboolean[count];
832
833 for(int i = 0; i < count; i++)
834 {
835 if(v[i] == 0)
836 {
837 boolParams[i] = GL_FALSE;
838 }
839 else
840 {
841 boolParams[i] = GL_TRUE;
842 }
843 }
844
845 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean),
846 boolParams, sizeof(GLboolean)* count);
847
848 delete[] boolParams;
849 }
850 else
851 {
852 return false;
853 }
854
855 return true;
856 }
857
858 bool Program::setUniformuiv(GLint location, GLsizei count, const GLuint *v, int numElements)
859 {
Nicolas Capens0bac2852016-05-07 06:09:58 -0400860 static GLenum uintType[] = { GL_UNSIGNED_INT, GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT_VEC3, GL_UNSIGNED_INT_VEC4 };
861 static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };
862
Alexis Hetuec5da192017-10-06 13:23:49 -0400863 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400864 {
865 return false;
866 }
867
868 Uniform *targetUniform = uniforms[uniformIndex[location].index];
869 targetUniform->dirty = true;
870
871 int size = targetUniform->size();
872
873 if(size == 1 && count > 1)
874 {
875 return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
876 }
877
878 count = std::min(size - (int)uniformIndex[location].element, count);
879
880 int index = numElements - 1;
Alexis Hetu3eb573f2017-11-22 13:27:03 -0500881 if(targetUniform->type == uintType[index])
Nicolas Capens0bac2852016-05-07 06:09:58 -0400882 {
883 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLuint)* numElements,
884 v, numElements * sizeof(GLuint)* count);
885 }
886 else if(targetUniform->type == boolType[index])
887 {
888 GLboolean *boolParams = new GLboolean[count * numElements];
889
890 for(int i = 0; i < count * numElements; i++)
891 {
892 boolParams[i] = (v[i] == 0) ? GL_FALSE : GL_TRUE;
893 }
894
895 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean)* numElements,
896 boolParams, numElements * sizeof(GLboolean)* count);
897
898 delete[] boolParams;
899 }
900 else
901 {
902 return false;
903 }
904
905 return true;
906 }
907
908 bool Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
909 {
910 return setUniformuiv(location, count, v, 2);
911 }
912
913 bool Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
914 {
915 return setUniformuiv(location, count, v, 3);
916 }
917
918 bool Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
919 {
920 return setUniformuiv(location, count, v, 4);
921 }
922
923 bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
924 {
Alexis Hetuec5da192017-10-06 13:23:49 -0400925 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400926 {
927 return false;
928 }
929
930 Uniform *targetUniform = uniforms[uniformIndex[location].index];
931 unsigned int count = UniformComponentCount(targetUniform->type);
932
933 // Sized query - ensure the provided buffer is large enough
934 if(bufSize && static_cast<unsigned int>(*bufSize) < count * sizeof(GLfloat))
935 {
936 return false;
937 }
938
939 switch(UniformComponentType(targetUniform->type))
940 {
941 case GL_BOOL:
942 {
943 GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * count;
944
945 for(unsigned int i = 0; i < count; i++)
946 {
947 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
948 }
949 }
950 break;
951 case GL_FLOAT:
952 memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLfloat),
953 count * sizeof(GLfloat));
954 break;
955 case GL_INT:
956 {
957 GLint *intParams = (GLint*)targetUniform->data + uniformIndex[location].element * count;
958
959 for(unsigned int i = 0; i < count; i++)
960 {
961 params[i] = (float)intParams[i];
962 }
963 }
964 break;
965 case GL_UNSIGNED_INT:
966 {
967 GLuint *uintParams = (GLuint*)targetUniform->data + uniformIndex[location].element * count;
968
969 for(unsigned int i = 0; i < count; i++)
970 {
971 params[i] = (float)uintParams[i];
972 }
973 }
974 break;
975 default: UNREACHABLE(targetUniform->type);
976 }
977
978 return true;
979 }
980
981 bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
982 {
Alexis Hetuec5da192017-10-06 13:23:49 -0400983 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400984 {
985 return false;
986 }
987
988 Uniform *targetUniform = uniforms[uniformIndex[location].index];
989 unsigned int count = UniformComponentCount(targetUniform->type);
990
991 // Sized query - ensure the provided buffer is large enough
992 if(bufSize && static_cast<unsigned int>(*bufSize) < count * sizeof(GLint))
993 {
994 return false;
995 }
996
997 switch(UniformComponentType(targetUniform->type))
998 {
999 case GL_BOOL:
1000 {
1001 GLboolean *boolParams = targetUniform->data + uniformIndex[location].element * count;
1002
1003 for(unsigned int i = 0; i < count; i++)
1004 {
1005 params[i] = (GLint)boolParams[i];
1006 }
1007 }
1008 break;
1009 case GL_FLOAT:
1010 {
1011 GLfloat *floatParams = (GLfloat*)targetUniform->data + uniformIndex[location].element * count;
1012
1013 for(unsigned int i = 0; i < count; i++)
1014 {
1015 params[i] = (GLint)floatParams[i];
1016 }
1017 }
1018 break;
1019 case GL_INT:
1020 case GL_UNSIGNED_INT:
1021 memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLint),
1022 count * sizeof(GLint));
1023 break;
1024 default: UNREACHABLE(targetUniform->type);
1025 }
1026
1027 return true;
1028 }
1029
1030 bool Program::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
1031 {
Alexis Hetuec5da192017-10-06 13:23:49 -04001032 if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -04001033 {
1034 return false;
1035 }
1036
1037 Uniform *targetUniform = uniforms[uniformIndex[location].index];
1038 unsigned int count = UniformComponentCount(targetUniform->type);
1039
1040 // Sized query - ensure the provided buffer is large enough
1041 if(bufSize && static_cast<unsigned int>(*bufSize) < count * sizeof(GLuint))
1042 {
1043 return false;
1044 }
1045
1046 switch(UniformComponentType(targetUniform->type))
1047 {
1048 case GL_BOOL:
1049 {
1050 GLboolean *boolParams = targetUniform->data + uniformIndex[location].element * count;
1051
1052 for(unsigned int i = 0; i < count; i++)
1053 {
1054 params[i] = (GLuint)boolParams[i];
1055 }
1056 }
1057 break;
1058 case GL_FLOAT:
1059 {
1060 GLfloat *floatParams = (GLfloat*)targetUniform->data + uniformIndex[location].element * count;
1061
1062 for(unsigned int i = 0; i < count; i++)
1063 {
1064 params[i] = (GLuint)floatParams[i];
1065 }
1066 }
1067 break;
1068 case GL_INT:
1069 case GL_UNSIGNED_INT:
1070 memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLuint),
1071 count * sizeof(GLuint));
1072 break;
1073 default: UNREACHABLE(targetUniform->type);
1074 }
1075
1076 return true;
1077 }
1078
1079 void Program::dirtyAllUniforms()
1080 {
1081 size_t numUniforms = uniforms.size();
1082 for(size_t index = 0; index < numUniforms; index++)
1083 {
1084 uniforms[index]->dirty = true;
1085 }
1086 }
1087
1088 // Applies all the uniforms set for this program object to the device
Ben Vanik1fd3b282017-07-10 14:08:12 -07001089 void Program::applyUniforms(Device *device)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001090 {
Alexis Hetu05c32b92016-06-23 11:32:07 -04001091 GLint numUniforms = static_cast<GLint>(uniformIndex.size());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001092 for(GLint location = 0; location < numUniforms; location++)
1093 {
Alexis Hetuec5da192017-10-06 13:23:49 -04001094 if((uniformIndex[location].element != 0) || (uniformIndex[location].index == GL_INVALID_INDEX))
Nicolas Capens0bac2852016-05-07 06:09:58 -04001095 {
1096 continue;
1097 }
1098
1099 Uniform *targetUniform = uniforms[uniformIndex[location].index];
1100
1101 if(targetUniform->dirty && (targetUniform->blockInfo.index == -1))
1102 {
1103 GLsizei size = targetUniform->size();
1104 GLfloat *f = (GLfloat*)targetUniform->data;
1105 GLint *i = (GLint*)targetUniform->data;
1106 GLuint *ui = (GLuint*)targetUniform->data;
1107 GLboolean *b = (GLboolean*)targetUniform->data;
1108
1109 switch(targetUniform->type)
1110 {
Ben Vanik1fd3b282017-07-10 14:08:12 -07001111 case GL_BOOL: applyUniform1bv(device, location, size, b); break;
1112 case GL_BOOL_VEC2: applyUniform2bv(device, location, size, b); break;
1113 case GL_BOOL_VEC3: applyUniform3bv(device, location, size, b); break;
1114 case GL_BOOL_VEC4: applyUniform4bv(device, location, size, b); break;
1115 case GL_FLOAT: applyUniform1fv(device, location, size, f); break;
1116 case GL_FLOAT_VEC2: applyUniform2fv(device, location, size, f); break;
1117 case GL_FLOAT_VEC3: applyUniform3fv(device, location, size, f); break;
1118 case GL_FLOAT_VEC4: applyUniform4fv(device, location, size, f); break;
1119 case GL_FLOAT_MAT2: applyUniformMatrix2fv(device, location, size, f); break;
1120 case GL_FLOAT_MAT2x3: applyUniformMatrix2x3fv(device, location, size, f); break;
1121 case GL_FLOAT_MAT2x4: applyUniformMatrix2x4fv(device, location, size, f); break;
1122 case GL_FLOAT_MAT3x2: applyUniformMatrix3x2fv(device, location, size, f); break;
1123 case GL_FLOAT_MAT3: applyUniformMatrix3fv(device, location, size, f); break;
1124 case GL_FLOAT_MAT3x4: applyUniformMatrix3x4fv(device, location, size, f); break;
1125 case GL_FLOAT_MAT4x2: applyUniformMatrix4x2fv(device, location, size, f); break;
1126 case GL_FLOAT_MAT4x3: applyUniformMatrix4x3fv(device, location, size, f); break;
1127 case GL_FLOAT_MAT4: applyUniformMatrix4fv(device, location, size, f); break;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001128 case GL_SAMPLER_2D:
1129 case GL_SAMPLER_CUBE:
Alexis Hetu46768622018-01-16 22:09:28 -05001130 case GL_SAMPLER_2D_RECT_ARB:
Nicolas Capens0bac2852016-05-07 06:09:58 -04001131 case GL_SAMPLER_EXTERNAL_OES:
1132 case GL_SAMPLER_3D_OES:
1133 case GL_SAMPLER_2D_ARRAY:
1134 case GL_SAMPLER_2D_SHADOW:
1135 case GL_SAMPLER_CUBE_SHADOW:
1136 case GL_SAMPLER_2D_ARRAY_SHADOW:
1137 case GL_INT_SAMPLER_2D:
1138 case GL_UNSIGNED_INT_SAMPLER_2D:
1139 case GL_INT_SAMPLER_CUBE:
1140 case GL_UNSIGNED_INT_SAMPLER_CUBE:
1141 case GL_INT_SAMPLER_3D:
1142 case GL_UNSIGNED_INT_SAMPLER_3D:
1143 case GL_INT_SAMPLER_2D_ARRAY:
1144 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
Ben Vanik1fd3b282017-07-10 14:08:12 -07001145 case GL_INT: applyUniform1iv(device, location, size, i); break;
1146 case GL_INT_VEC2: applyUniform2iv(device, location, size, i); break;
1147 case GL_INT_VEC3: applyUniform3iv(device, location, size, i); break;
1148 case GL_INT_VEC4: applyUniform4iv(device, location, size, i); break;
1149 case GL_UNSIGNED_INT: applyUniform1uiv(device, location, size, ui); break;
1150 case GL_UNSIGNED_INT_VEC2: applyUniform2uiv(device, location, size, ui); break;
1151 case GL_UNSIGNED_INT_VEC3: applyUniform3uiv(device, location, size, ui); break;
1152 case GL_UNSIGNED_INT_VEC4: applyUniform4uiv(device, location, size, ui); break;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001153 default:
1154 UNREACHABLE(targetUniform->type);
1155 }
1156
1157 targetUniform->dirty = false;
1158 }
1159 }
1160 }
1161
Ben Vanik1fd3b282017-07-10 14:08:12 -07001162 void Program::applyUniformBuffers(Device *device, BufferBinding* uniformBuffers)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001163 {
1164 GLint vertexUniformBuffers[MAX_UNIFORM_BUFFER_BINDINGS];
1165 GLint fragmentUniformBuffers[MAX_UNIFORM_BUFFER_BINDINGS];
1166
1167 for(unsigned int bufferBindingIndex = 0; bufferBindingIndex < MAX_UNIFORM_BUFFER_BINDINGS; bufferBindingIndex++)
1168 {
1169 vertexUniformBuffers[bufferBindingIndex] = -1;
1170 }
1171
1172 for(unsigned int bufferBindingIndex = 0; bufferBindingIndex < MAX_UNIFORM_BUFFER_BINDINGS; bufferBindingIndex++)
1173 {
1174 fragmentUniformBuffers[bufferBindingIndex] = -1;
1175 }
1176
1177 int vertexUniformBufferIndex = 0;
1178 int fragmentUniformBufferIndex = 0;
1179 for(unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlocks.size(); uniformBlockIndex++)
1180 {
1181 UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];
1182
1183 // Unnecessary to apply an unreferenced standard or shared UBO
1184 if(!uniformBlock.isReferencedByVertexShader() && !uniformBlock.isReferencedByFragmentShader())
1185 {
1186 continue;
1187 }
1188
1189 GLuint blockBinding = uniformBlockBindings[uniformBlockIndex];
1190
1191 if(uniformBlock.isReferencedByVertexShader())
1192 {
1193 vertexUniformBuffers[vertexUniformBufferIndex++] = blockBinding;
1194 }
1195
1196 if(uniformBlock.isReferencedByFragmentShader())
1197 {
1198 fragmentUniformBuffers[fragmentUniformBufferIndex++] = blockBinding;
1199 }
1200 }
1201
1202 for(unsigned int bufferBindingIndex = 0; bufferBindingIndex < MAX_UNIFORM_BUFFER_BINDINGS; bufferBindingIndex++)
1203 {
1204 int index = vertexUniformBuffers[bufferBindingIndex];
Alexis Hetu20c0f652016-09-21 09:11:44 -04001205 Buffer* vsBuffer = (index != -1) ? (Buffer*)uniformBuffers[index].get() : nullptr;
1206 device->VertexProcessor::setUniformBuffer(bufferBindingIndex,
1207 vsBuffer ? vsBuffer->getResource() : nullptr, (index != -1) ? uniformBuffers[index].getOffset() : 0);
1208 index = fragmentUniformBuffers[bufferBindingIndex];
1209 Buffer* psBuffer = (index != -1) ? (Buffer*)uniformBuffers[index].get() : nullptr;
1210 device->PixelProcessor::setUniformBuffer(bufferBindingIndex,
1211 psBuffer ? psBuffer->getResource() : nullptr, (index != -1) ? uniformBuffers[index].getOffset() : 0);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001212 }
1213 }
1214
Ben Vanik1fd3b282017-07-10 14:08:12 -07001215 void Program::applyTransformFeedback(Device *device, TransformFeedback* transformFeedback)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001216 {
1217 // Make sure the flags will fit in a 64 bit unsigned int variable
1218 ASSERT(sw::max<int>(MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS) <= 64);
1219
1220 BufferBinding* transformFeedbackBuffers = (transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused()) ? transformFeedback->getBuffers() : nullptr;
1221
1222 uint64_t enableTransformFeedback = 0;
1223 if(!transformFeedbackBuffers)
1224 {
1225 for(unsigned int index = 0; index < sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; ++index)
1226 {
1227 device->VertexProcessor::setTransformFeedbackBuffer(index, nullptr, 0, 0, 0, 0, 0);
1228 }
1229 device->VertexProcessor::enableTransformFeedback(enableTransformFeedback);
1230 return;
1231 }
1232
Alexis Hetu05c32b92016-06-23 11:32:07 -04001233 unsigned int maxVaryings = static_cast<unsigned int>(transformFeedbackLinkedVaryings.size());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001234 switch(transformFeedbackBufferMode)
1235 {
1236 case GL_SEPARATE_ATTRIBS:
1237 {
1238 maxVaryings = sw::min(maxVaryings, (unsigned int)MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS);
1239 // Attribs go to separate buffers
1240 for(unsigned int index = 0; index < maxVaryings; ++index)
1241 {
1242 int size = transformFeedbackLinkedVaryings[index].size;
1243 int rowCount = VariableRowCount(transformFeedbackLinkedVaryings[index].type);
1244 int colCount = VariableColumnCount(transformFeedbackLinkedVaryings[index].type);
1245 int nbRegs = rowCount > 1 ? colCount * size : size;
1246 int nbComponentsPerReg = rowCount > 1 ? rowCount : colCount;
1247 int componentStride = rowCount * colCount * size;
1248 int baseOffset = transformFeedback->vertexOffset() * componentStride * sizeof(float);
1249 device->VertexProcessor::setTransformFeedbackBuffer(index,
1250 transformFeedbackBuffers[index].get()->getResource(),
1251 transformFeedbackBuffers[index].getOffset() + baseOffset,
1252 transformFeedbackLinkedVaryings[index].reg * 4 + transformFeedbackLinkedVaryings[index].col,
1253 nbRegs, nbComponentsPerReg, componentStride);
1254 enableTransformFeedback |= 1ULL << index;
1255 }
1256 }
1257 break;
1258 case GL_INTERLEAVED_ATTRIBS:
1259 {
1260 // OpenGL ES 3.0.4 spec, section 2.15.2:
1261 // In INTERLEAVED_ATTRIBS mode, the values of one or more output variables
1262 // written by a vertex shader are written, interleaved, into the buffer object
1263 // bound to the first transform feedback binding point (index = 0).
1264 sw::Resource* resource = transformFeedbackBuffers[0].get()->getResource();
Alexis Hetu05c32b92016-06-23 11:32:07 -04001265 int componentStride = static_cast<int>(totalLinkedVaryingsComponents);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001266 int baseOffset = transformFeedbackBuffers[0].getOffset() + (transformFeedback->vertexOffset() * componentStride * sizeof(float));
1267 maxVaryings = sw::min(maxVaryings, (unsigned int)sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS);
Alexis Hetu05c32b92016-06-23 11:32:07 -04001268 int totalComponents = 0;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001269 for(unsigned int index = 0; index < maxVaryings; ++index)
1270 {
1271 int size = transformFeedbackLinkedVaryings[index].size;
1272 int rowCount = VariableRowCount(transformFeedbackLinkedVaryings[index].type);
1273 int colCount = VariableColumnCount(transformFeedbackLinkedVaryings[index].type);
1274 int nbRegs = rowCount > 1 ? colCount * size : size;
1275 int nbComponentsPerReg = rowCount > 1 ? rowCount : colCount;
1276 device->VertexProcessor::setTransformFeedbackBuffer(index, resource,
1277 baseOffset + (totalComponents * sizeof(float)),
1278 transformFeedbackLinkedVaryings[index].reg * 4 + transformFeedbackLinkedVaryings[index].col,
1279 nbRegs, nbComponentsPerReg, componentStride);
1280 totalComponents += rowCount * colCount * size;
1281 enableTransformFeedback |= 1ULL << index;
1282 }
1283 }
1284 break;
1285 default:
1286 UNREACHABLE(transformFeedbackBufferMode);
1287 break;
1288 }
1289
1290 // Unset all other transform feedback buffers
1291 for(unsigned int index = maxVaryings; index < sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; ++index)
1292 {
1293 device->VertexProcessor::setTransformFeedbackBuffer(index, nullptr, 0, 0, 0, 0, 0);
1294 }
1295
1296 device->VertexProcessor::enableTransformFeedback(enableTransformFeedback);
1297 }
1298
1299 bool Program::linkVaryings()
1300 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001301 glsl::VaryingList &psVaryings = fragmentShader->varyings;
1302 glsl::VaryingList &vsVaryings = vertexShader->varyings;
1303
1304 for(auto const &input : psVaryings)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001305 {
1306 bool matched = false;
1307
Alexis Hetu23f54d72017-12-05 16:03:51 -05001308 for(auto const &output : vsVaryings)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001309 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001310 if(output.name == input.name)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001311 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001312 if(output.type != input.type || output.size() != input.size())
Nicolas Capens0bac2852016-05-07 06:09:58 -04001313 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001314 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 -04001315
1316 return false;
1317 }
1318
Alexis Hetu743913c2018-01-04 11:54:55 -05001319 if((output.qualifier == EvqFlatOut) ^ (input.qualifier == EvqFlatIn))
1320 {
1321 appendToInfoLog("Interpolation qualifiers for %s differ between vertex and fragment shaders", output.name.c_str());
1322
1323 return false;
1324 }
1325
Alexis Hetu924513c2018-01-05 15:48:12 -05001326 if(!areMatchingFields(input.fields, output.fields, input.name))
1327 {
1328 return false;
1329 }
1330
Nicolas Capens0bac2852016-05-07 06:09:58 -04001331 matched = true;
1332 break;
1333 }
1334 }
1335
1336 if(!matched)
1337 {
Nicolas Capens6896e352018-01-10 12:46:52 -05001338 // If a fragment varying is declared but not statically used, it's not an error to not have a matching vertex varying.
1339 if(input.registerIndex >= 0)
1340 {
1341 appendToInfoLog("Fragment varying %s does not match any vertex varying", input.name.c_str());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001342
Nicolas Capens6896e352018-01-10 12:46:52 -05001343 return false;
1344 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001345 }
1346 }
1347
Alexis Hetu23f54d72017-12-05 16:03:51 -05001348 for(auto const &output : vsVaryings)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001349 {
Alexis Hetu144974d2016-04-05 17:31:32 -04001350 bool matched = false;
1351
Alexis Hetu23f54d72017-12-05 16:03:51 -05001352 for(auto const &input : psVaryings)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001353 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001354 if(output.name == input.name)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001355 {
Alexis Hetu924513c2018-01-05 15:48:12 -05001356 int in = input.registerIndex;
1357 int out = output.registerIndex;
Alexis Hetu23f54d72017-12-05 16:03:51 -05001358 int components = VariableRegisterSize(output.type);
1359 int registers = VariableRegisterCount(output.type) * output.size();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001360
Nicolas Capens88e7dcf2018-01-11 14:46:12 -05001361 if(in < 0) // Fragment varying declared but not used
1362 {
1363 continue;
1364 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001365
Nicolas Capens88e7dcf2018-01-11 14:46:12 -05001366 if(in + registers >= MAX_VARYING_VECTORS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001367 {
1368 appendToInfoLog("Too many varyings");
1369 return false;
1370 }
1371
1372 if(out >= 0)
1373 {
Nicolas Capens88e7dcf2018-01-11 14:46:12 -05001374 if(out + registers >= MAX_VARYING_VECTORS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001375 {
1376 appendToInfoLog("Too many varyings");
1377 return false;
1378 }
1379
1380 for(int i = 0; i < registers; i++)
1381 {
Alexis Hetu02ad0aa2016-08-02 11:18:14 -04001382 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 -04001383 }
1384 }
1385 else // Vertex varying is declared but not written to
1386 {
1387 for(int i = 0; i < registers; i++)
1388 {
Alexis Hetu02ad0aa2016-08-02 11:18:14 -04001389 pixelBinary->setInput(in + i, components, sw::Shader::Semantic());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001390 }
1391 }
1392
Alexis Hetu144974d2016-04-05 17:31:32 -04001393 matched = true;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001394 break;
1395 }
1396 }
Alexis Hetu144974d2016-04-05 17:31:32 -04001397
Alexis Hetuec92f3c2017-05-23 17:10:09 -04001398 if(!matched)
Alexis Hetu144974d2016-04-05 17:31:32 -04001399 {
Alexis Hetuec92f3c2017-05-23 17:10:09 -04001400 // For openGL ES 3.0, we need to still add the vertex shader outputs for unmatched varyings, for transform feedback.
1401 for(const std::string &indexedTfVaryingName : transformFeedbackVaryings)
Alexis Hetu144974d2016-04-05 17:31:32 -04001402 {
Alexis Hetuec92f3c2017-05-23 17:10:09 -04001403 std::string tfVaryingName = es2::ParseUniformName(indexedTfVaryingName, nullptr);
Alexis Hetu144974d2016-04-05 17:31:32 -04001404
Alexis Hetu23f54d72017-12-05 16:03:51 -05001405 if(tfVaryingName == output.name)
Alexis Hetu144974d2016-04-05 17:31:32 -04001406 {
Alexis Hetu924513c2018-01-05 15:48:12 -05001407 int out = output.registerIndex;
Alexis Hetu23f54d72017-12-05 16:03:51 -05001408 int components = VariableRegisterSize(output.type);
1409 int registers = VariableRegisterCount(output.type) * output.size();
Alexis Hetuec92f3c2017-05-23 17:10:09 -04001410
1411 if(out >= 0)
1412 {
Nicolas Capens88e7dcf2018-01-11 14:46:12 -05001413 if(out + registers >= MAX_VARYING_VECTORS)
Alexis Hetuec92f3c2017-05-23 17:10:09 -04001414 {
1415 appendToInfoLog("Too many varyings");
1416 return false;
1417 }
1418
1419 for(int i = 0; i < registers; i++)
1420 {
1421 vertexBinary->setOutput(out + i, components, sw::Shader::Semantic(sw::Shader::USAGE_COLOR));
1422 }
1423 }
1424 break;
Alexis Hetu144974d2016-04-05 17:31:32 -04001425 }
1426 }
1427 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001428 }
1429
1430 return true;
1431 }
1432
1433 bool Program::linkTransformFeedback()
1434 {
1435 size_t totalComponents = 0;
1436 totalLinkedVaryingsComponents = 0;
1437
1438 std::set<std::string> uniqueNames;
1439
1440 for(const std::string &indexedTfVaryingName : transformFeedbackVaryings)
1441 {
Alexis Hetu53977f12016-06-27 16:04:31 -04001442 unsigned int subscript = GL_INVALID_INDEX;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001443 std::string tfVaryingName = es2::ParseUniformName(indexedTfVaryingName, &subscript);
1444 bool hasSubscript = (subscript != GL_INVALID_INDEX);
1445
1446 if(tfVaryingName.find('[') != std::string::npos)
1447 {
1448 appendToInfoLog("Capture of array sub-elements is undefined and not supported.");
1449 return false;
1450 }
1451
1452 bool found = false;
1453 for(const glsl::Varying varying : vertexShader->varyings)
1454 {
1455 if(tfVaryingName == varying.name)
1456 {
1457 if(uniqueNames.count(indexedTfVaryingName) > 0)
1458 {
1459 appendToInfoLog("Two transform feedback varyings specify the same output variable (%s)", indexedTfVaryingName.c_str());
1460 return false;
1461 }
1462 uniqueNames.insert(indexedTfVaryingName);
1463
1464 if(hasSubscript && ((static_cast<int>(subscript)) >= varying.size()))
1465 {
1466 appendToInfoLog("Specified transform feedback varying index out of bounds (%s)", indexedTfVaryingName.c_str());
1467 return false;
1468 }
1469
Alexis Hetu05c32b92016-06-23 11:32:07 -04001470 int size = hasSubscript ? 1 : varying.size();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001471
Alexis Hetu05c32b92016-06-23 11:32:07 -04001472 int rowCount = VariableRowCount(varying.type);
1473 int colCount = VariableColumnCount(varying.type);
1474 int componentCount = rowCount * colCount * size;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001475 if(transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
1476 componentCount > sw::MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS)
1477 {
1478 appendToInfoLog("Transform feedback varying's %s components (%d) exceed the maximum separate components (%d).",
1479 varying.name.c_str(), componentCount, sw::MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS);
1480 return false;
1481 }
1482
1483 totalComponents += componentCount;
1484
Alexis Hetu924513c2018-01-05 15:48:12 -05001485 int reg = varying.registerIndex;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001486 if(hasSubscript)
1487 {
1488 reg += rowCount > 1 ? colCount * subscript : subscript;
1489 }
Alexis Hetuc67e57e2018-01-09 16:44:59 -05001490 int col = varying.column;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001491 if(tfVaryingName == "gl_PointSize")
1492 {
1493 // Point size is stored in the y element of the vector, not the x element
1494 col = 1; // FIXME: varying.col could already contain this information
1495 }
1496 transformFeedbackLinkedVaryings.push_back(LinkedVarying(varying.name, varying.type, size, reg, col));
1497
1498 found = true;
1499 break;
1500 }
1501 }
1502
1503 if(!found)
1504 {
1505 appendToInfoLog("Transform feedback varying %s does not exist in the vertex shader.", tfVaryingName.c_str());
1506 return false;
1507 }
1508 }
1509
1510 if(transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
1511 totalComponents > sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS)
1512 {
1513 appendToInfoLog("Transform feedback varying total components (%d) exceed the maximum separate components (%d).",
1514 totalComponents, sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS);
1515 return false;
1516 }
1517
1518 totalLinkedVaryingsComponents = totalComponents;
1519
1520 return true;
1521 }
1522
1523 // Links the code of the vertex and pixel shader by matching up their varyings,
1524 // compiling them into binaries, determining the attribute mappings, and collecting
1525 // a list of uniforms
1526 void Program::link()
1527 {
1528 unlink();
1529
1530 resetUniformBlockBindings();
1531
1532 if(!fragmentShader || !fragmentShader->isCompiled())
1533 {
1534 return;
1535 }
1536
1537 if(!vertexShader || !vertexShader->isCompiled())
1538 {
1539 return;
1540 }
1541
1542 vertexBinary = new sw::VertexShader(vertexShader->getVertexShader());
1543 pixelBinary = new sw::PixelShader(fragmentShader->getPixelShader());
1544
1545 if(!linkVaryings())
1546 {
1547 return;
1548 }
1549
1550 if(!linkAttributes())
1551 {
1552 return;
1553 }
1554
1555 // Link uniform blocks before uniforms to make it easy to assign block indices to fields
1556 if(!linkUniformBlocks(vertexShader, fragmentShader))
1557 {
1558 return;
1559 }
1560
1561 if(!linkUniforms(fragmentShader))
1562 {
1563 return;
1564 }
1565
1566 if(!linkUniforms(vertexShader))
1567 {
1568 return;
1569 }
1570
1571 if(!linkTransformFeedback())
1572 {
1573 return;
1574 }
1575
1576 linked = true; // Success
1577 }
1578
1579 // Determines the mapping between GL attributes and vertex stream usage indices
1580 bool Program::linkAttributes()
1581 {
Nicolas Capens378c4342018-08-07 23:57:21 -04001582 static_assert(MAX_VERTEX_ATTRIBS <= 32, "attribute count exceeds bitfield count");
Nicolas Capens0bac2852016-05-07 06:09:58 -04001583 unsigned int usedLocations = 0;
1584
Nicolas Capens378c4342018-08-07 23:57:21 -04001585 // Link attributes that have a GLSL layout location qualifier
Alexis Hetu23f54d72017-12-05 16:03:51 -05001586 for(auto const &attribute : vertexShader->activeAttributes)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001587 {
Nicolas Capens378c4342018-08-07 23:57:21 -04001588 if(attribute.layoutLocation != -1)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001589 {
Nicolas Capens378c4342018-08-07 23:57:21 -04001590 if(!linkAttribute(attribute, attribute.layoutLocation, usedLocations))
Nicolas Capens0bac2852016-05-07 06:09:58 -04001591 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04001592 return false;
1593 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001594 }
1595 }
1596
Nicolas Capens378c4342018-08-07 23:57:21 -04001597 // Link attributes that have an API provided binding location but no GLSL layout location
Alexis Hetu23f54d72017-12-05 16:03:51 -05001598 for(auto const &attribute : vertexShader->activeAttributes)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001599 {
Nicolas Capens378c4342018-08-07 23:57:21 -04001600 int bindingLocation = (attributeBinding.find(attribute.name) != attributeBinding.end()) ? attributeBinding[attribute.name] : -1;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001601
Nicolas Capens378c4342018-08-07 23:57:21 -04001602 if(attribute.layoutLocation == -1 && bindingLocation != -1)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001603 {
Nicolas Capens378c4342018-08-07 23:57:21 -04001604 if(!linkAttribute(attribute, bindingLocation, usedLocations))
Nicolas Capens0bac2852016-05-07 06:09:58 -04001605 {
Nicolas Capens378c4342018-08-07 23:57:21 -04001606 return false;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001607 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001608 }
1609 }
1610
Nicolas Capens378c4342018-08-07 23:57:21 -04001611 // Link attributes that don't have a binding location nor a layout location
1612 for(auto const &attribute : vertexShader->activeAttributes)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001613 {
Nicolas Capens378c4342018-08-07 23:57:21 -04001614 if(attribute.layoutLocation == -1 && attributeBinding.find(attribute.name) == attributeBinding.end())
1615 {
1616 if(!linkAttribute(attribute, -1, usedLocations))
1617 {
1618 return false;
1619 }
1620 }
1621 }
1622
1623 ASSERT(linkedAttribute.size() == vertexShader->activeAttributes.size());
1624
1625 for(auto const &attribute : linkedAttribute)
1626 {
1627 int location = getAttributeLocation(attribute.name);
Alexis Hetu23f54d72017-12-05 16:03:51 -05001628 ASSERT(location >= 0);
Nicolas Capens378c4342018-08-07 23:57:21 -04001629 int index = vertexShader->getSemanticIndex(attribute.name);
1630 int rows = VariableRegisterCount(attribute.type);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001631
1632 for(int r = 0; r < rows; r++)
1633 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05001634 attributeStream[r + location] = index++;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001635 }
1636 }
1637
1638 return true;
1639 }
1640
Nicolas Capens378c4342018-08-07 23:57:21 -04001641 bool Program::linkAttribute(const glsl::Attribute &attribute, int location, unsigned int &usedLocations)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001642 {
Nicolas Capens378c4342018-08-07 23:57:21 -04001643 int rows = VariableRegisterCount(attribute.type);
1644
1645 if(location == -1)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001646 {
Nicolas Capens378c4342018-08-07 23:57:21 -04001647 location = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1648
1649 if(location == -1 || location + rows > MAX_VERTEX_ATTRIBS)
1650 {
1651 appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
1652 return false; // Fail to link
1653 }
1654 }
1655 else
1656 {
1657 if(rows + location > MAX_VERTEX_ATTRIBS)
1658 {
1659 appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
1660 return false;
1661 }
1662
1663 // In GLSL 3.00, attribute aliasing produces a link error
1664 // In GLSL 1.00, attribute aliasing is allowed
1665 if(vertexShader->getShaderVersion() >= 300)
1666 {
1667 for(auto const &previousAttrib : linkedAttribute)
1668 {
1669 int previousLocation = getAttributeLocation(previousAttrib.name);
1670 int previousRows = VariableRegisterCount(previousAttrib.type);
1671
1672 if(location >= previousLocation && location < previousLocation + previousRows)
1673 {
1674 appendToInfoLog("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), previousAttrib.name.c_str(), location);
1675 return false;
1676 }
1677
1678 if(location <= previousLocation && location + rows > previousLocation)
1679 {
1680 appendToInfoLog("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), previousAttrib.name.c_str(), previousLocation);
1681 return false;
1682 }
1683 }
1684 }
1685
1686 for(int i = 0; i < rows; i++)
1687 {
1688 usedLocations |= 1 << (location + i);
1689 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001690 }
1691
Nicolas Capens378c4342018-08-07 23:57:21 -04001692 linkedAttributeLocation[attribute.name] = location;
1693 linkedAttribute.push_back(attribute);
1694
1695 return true;
1696 }
1697
1698 int Program::getAttributeLocation(const std::string &name)
1699 {
1700 std::map<std::string, GLuint>::const_iterator attribute = linkedAttributeLocation.find(name);
1701 if(attribute != linkedAttributeLocation.end())
Nicolas Capens0bac2852016-05-07 06:09:58 -04001702 {
Nicolas Capens378c4342018-08-07 23:57:21 -04001703 return attribute->second;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001704 }
1705
1706 return -1;
1707 }
1708
1709 bool Program::linkUniforms(const Shader *shader)
1710 {
Alexis Hetu924513c2018-01-05 15:48:12 -05001711 for(const auto &uniform : shader->activeUniforms)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001712 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04001713 unsigned int blockIndex = GL_INVALID_INDEX;
1714 if(uniform.blockId >= 0)
1715 {
1716 const glsl::ActiveUniformBlocks &activeUniformBlocks = shader->activeUniformBlocks;
1717 ASSERT(static_cast<size_t>(uniform.blockId) < activeUniformBlocks.size());
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04001718 const std::string &uniformBlockName = activeUniformBlocks[uniform.blockId].name;
1719 blockIndex = getUniformBlockIndex(uniformBlockName);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001720 ASSERT(blockIndex != GL_INVALID_INDEX);
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04001721
1722 if(activeUniformBlocks[uniform.blockId].dataSize > MAX_UNIFORM_BLOCK_SIZE)
1723 {
1724 if(shader->getType() == GL_VERTEX_SHADER)
1725 {
1726 appendToInfoLog("Vertex shader active uniform block (%s) exceeds GL_MAX_UNIFORM_BLOCK_SIZE (%d)", uniformBlockName.c_str(), MAX_UNIFORM_BLOCK_SIZE);
1727 return false;
1728 }
1729 else if(shader->getType() == GL_FRAGMENT_SHADER)
1730 {
1731 appendToInfoLog("Fragment shader active uniform block (%s) exceeds GL_MAX_UNIFORM_BLOCK_SIZE (%d)", uniformBlockName.c_str(), MAX_UNIFORM_BLOCK_SIZE);
1732 return false;
1733 }
1734 else UNREACHABLE(shader->getType());
1735 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001736 }
Nicolas Capens0d8993c2018-07-16 11:13:49 -04001737
Alexis Hetu924513c2018-01-05 15:48:12 -05001738 if(!defineUniform(shader->getType(), uniform, Uniform::BlockInfo(uniform, blockIndex)))
1739 {
1740 return false;
1741 }
1742 }
1743
1744 for(const auto &uniformStruct : shader->activeUniformStructs)
1745 {
1746 if(!validateUniformStruct(shader->getType(), uniformStruct))
Nicolas Capens0bac2852016-05-07 06:09:58 -04001747 {
1748 return false;
1749 }
1750 }
1751
1752 return true;
1753 }
1754
Alexis Hetu924513c2018-01-05 15:48:12 -05001755 bool Program::defineUniform(GLenum shader, const glsl::Uniform &glslUniform, const Uniform::BlockInfo& blockInfo)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001756 {
Alexis Hetu924513c2018-01-05 15:48:12 -05001757 if(IsSamplerUniform(glslUniform.type))
Nicolas Capens0d8993c2018-07-16 11:13:49 -04001758 {
Alexis Hetu924513c2018-01-05 15:48:12 -05001759 int index = glslUniform.registerIndex;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001760
1761 do
1762 {
1763 if(shader == GL_VERTEX_SHADER)
1764 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00001765 if(index < MAX_VERTEX_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001766 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00001767 samplersVS[index].active = true;
1768
Alexis Hetu924513c2018-01-05 15:48:12 -05001769 switch(glslUniform.type)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001770 {
Alexis Hetu924513c2018-01-05 15:48:12 -05001771 default: UNREACHABLE(glslUniform.type);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001772 case GL_INT_SAMPLER_2D:
1773 case GL_UNSIGNED_INT_SAMPLER_2D:
1774 case GL_SAMPLER_2D_SHADOW:
1775 case GL_SAMPLER_2D: samplersVS[index].textureType = TEXTURE_2D; break;
1776 case GL_INT_SAMPLER_CUBE:
1777 case GL_UNSIGNED_INT_SAMPLER_CUBE:
1778 case GL_SAMPLER_CUBE_SHADOW:
1779 case GL_SAMPLER_CUBE: samplersVS[index].textureType = TEXTURE_CUBE; break;
1780 case GL_INT_SAMPLER_3D:
1781 case GL_UNSIGNED_INT_SAMPLER_3D:
1782 case GL_SAMPLER_3D_OES: samplersVS[index].textureType = TEXTURE_3D; break;
Alexis Hetu46768622018-01-16 22:09:28 -05001783 case GL_SAMPLER_2D_RECT_ARB: samplersVS[index].textureType = TEXTURE_2D_RECT; break;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001784 case GL_SAMPLER_EXTERNAL_OES: samplersVS[index].textureType = TEXTURE_EXTERNAL; break;
1785 case GL_INT_SAMPLER_2D_ARRAY:
1786 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
1787 case GL_SAMPLER_2D_ARRAY_SHADOW:
1788 case GL_SAMPLER_2D_ARRAY: samplersVS[index].textureType = TEXTURE_2D_ARRAY; break;
1789 }
1790
1791 samplersVS[index].logicalTextureUnit = 0;
1792 }
1793 else
1794 {
1795 appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", MAX_VERTEX_TEXTURE_IMAGE_UNITS);
1796 return false;
1797 }
1798 }
1799 else if(shader == GL_FRAGMENT_SHADER)
1800 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00001801 if(index < MAX_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001802 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00001803 samplersPS[index].active = true;
1804
Alexis Hetu924513c2018-01-05 15:48:12 -05001805 switch(glslUniform.type)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001806 {
Alexis Hetu924513c2018-01-05 15:48:12 -05001807 default: UNREACHABLE(glslUniform.type);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001808 case GL_INT_SAMPLER_2D:
1809 case GL_UNSIGNED_INT_SAMPLER_2D:
1810 case GL_SAMPLER_2D_SHADOW:
1811 case GL_SAMPLER_2D: samplersPS[index].textureType = TEXTURE_2D; break;
1812 case GL_INT_SAMPLER_CUBE:
1813 case GL_UNSIGNED_INT_SAMPLER_CUBE:
1814 case GL_SAMPLER_CUBE_SHADOW:
1815 case GL_SAMPLER_CUBE: samplersPS[index].textureType = TEXTURE_CUBE; break;
1816 case GL_INT_SAMPLER_3D:
1817 case GL_UNSIGNED_INT_SAMPLER_3D:
1818 case GL_SAMPLER_3D_OES: samplersPS[index].textureType = TEXTURE_3D; break;
Alexis Hetu46768622018-01-16 22:09:28 -05001819 case GL_SAMPLER_2D_RECT_ARB: samplersPS[index].textureType = TEXTURE_2D_RECT; break;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001820 case GL_SAMPLER_EXTERNAL_OES: samplersPS[index].textureType = TEXTURE_EXTERNAL; break;
1821 case GL_INT_SAMPLER_2D_ARRAY:
1822 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
1823 case GL_SAMPLER_2D_ARRAY_SHADOW:
1824 case GL_SAMPLER_2D_ARRAY: samplersPS[index].textureType = TEXTURE_2D_ARRAY; break;
1825 }
1826
1827 samplersPS[index].logicalTextureUnit = 0;
1828 }
1829 else
1830 {
1831 appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
1832 return false;
1833 }
1834 }
1835 else UNREACHABLE(shader);
1836
1837 index++;
1838 }
Alexis Hetu924513c2018-01-05 15:48:12 -05001839 while(index < glslUniform.registerIndex + static_cast<int>(glslUniform.arraySize));
Nicolas Capens0d8993c2018-07-16 11:13:49 -04001840 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001841
Nicolas Capens0d8993c2018-07-16 11:13:49 -04001842 Uniform *uniform = getUniform(glslUniform.name);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001843
Nicolas Capens0d8993c2018-07-16 11:13:49 -04001844 if(!uniform)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001845 {
Nicolas Capens0d8993c2018-07-16 11:13:49 -04001846 uniform = new Uniform(glslUniform, blockInfo);
1847 uniforms.push_back(uniform);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001848
Nicolas Capens0d8993c2018-07-16 11:13:49 -04001849 unsigned int index = (blockInfo.index == -1) ? static_cast<unsigned int>(uniforms.size() - 1) : GL_INVALID_INDEX;
1850
1851 for(int i = 0; i < uniform->size(); i++)
1852 {
1853 uniformIndex.push_back(UniformLocation(glslUniform.name, i, index));
1854 }
1855 }
1856 else // Previously defined, types must match
1857 {
Alexis Hetu924513c2018-01-05 15:48:12 -05001858 if(uniform->type != glslUniform.type)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001859 {
1860 appendToInfoLog("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
1861 return false;
1862 }
1863
Alexis Hetu924513c2018-01-05 15:48:12 -05001864 if(uniform->precision != glslUniform.precision)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001865 {
1866 appendToInfoLog("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
1867 return false;
1868 }
Alexis Hetu924513c2018-01-05 15:48:12 -05001869
1870 if(!areMatchingFields(uniform->fields, glslUniform.fields, uniform->name))
1871 {
1872 return false;
1873 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001874 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001875
1876 if(shader == GL_VERTEX_SHADER)
1877 {
Alexis Hetu924513c2018-01-05 15:48:12 -05001878 uniform->vsRegisterIndex = glslUniform.registerIndex;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001879 }
1880 else if(shader == GL_FRAGMENT_SHADER)
1881 {
Alexis Hetu924513c2018-01-05 15:48:12 -05001882 uniform->psRegisterIndex = glslUniform.registerIndex;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001883 }
1884 else UNREACHABLE(shader);
1885
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04001886 if(uniform->blockInfo.index < 0)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001887 {
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04001888 if(shader == GL_VERTEX_SHADER)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001889 {
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04001890 if(glslUniform.registerIndex + uniform->registerCount() > MAX_VERTEX_UNIFORM_VECTORS)
1891 {
1892 appendToInfoLog("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%d)", MAX_VERTEX_UNIFORM_VECTORS);
1893 return false;
1894 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001895 }
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04001896 else if(shader == GL_FRAGMENT_SHADER)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001897 {
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04001898 if(glslUniform.registerIndex + uniform->registerCount() > MAX_FRAGMENT_UNIFORM_VECTORS)
1899 {
1900 appendToInfoLog("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%d)", MAX_FRAGMENT_UNIFORM_VECTORS);
1901 return false;
1902 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001903 }
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04001904 else UNREACHABLE(shader);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001905 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001906
1907 return true;
1908 }
1909
Alexis Hetu924513c2018-01-05 15:48:12 -05001910 bool Program::validateUniformStruct(GLenum shader, const glsl::Uniform &newUniformStruct)
1911 {
1912 for(const auto &uniformStruct : uniformStructs)
1913 {
1914 if(uniformStruct.name == newUniformStruct.name)
1915 {
1916 return areMatchingFields(uniformStruct.fields, newUniformStruct.fields, newUniformStruct.name);
1917 }
1918 }
1919
1920 uniformStructs.push_back(Uniform(newUniformStruct, Uniform::BlockInfo(newUniformStruct, -1)));
1921
1922 return true;
1923 }
1924
Nicolas Capens0bac2852016-05-07 06:09:58 -04001925 bool Program::areMatchingUniformBlocks(const glsl::UniformBlock &block1, const glsl::UniformBlock &block2, const Shader *shader1, const Shader *shader2)
1926 {
1927 // validate blocks for the same member types
1928 if(block1.fields.size() != block2.fields.size())
1929 {
Alexis Hetubc648b92018-01-04 17:39:15 -05001930 appendToInfoLog("Types for interface block '%s' differ between vertex and fragment shaders", block1.name.c_str());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001931 return false;
1932 }
1933 if(block1.arraySize != block2.arraySize)
1934 {
Alexis Hetubc648b92018-01-04 17:39:15 -05001935 appendToInfoLog("Array sizes differ for interface block '%s' between vertex and fragment shaders", block1.name.c_str());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001936 return false;
1937 }
1938 if(block1.layout != block2.layout || block1.isRowMajorLayout != block2.isRowMajorLayout)
1939 {
Alexis Hetubc648b92018-01-04 17:39:15 -05001940 appendToInfoLog("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", block1.name.c_str());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001941 return false;
1942 }
1943 const size_t numBlockMembers = block1.fields.size();
1944 for(size_t blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
1945 {
1946 const glsl::Uniform& member1 = shader1->activeUniforms[block1.fields[blockMemberIndex]];
1947 const glsl::Uniform& member2 = shader2->activeUniforms[block2.fields[blockMemberIndex]];
Alexis Hetubc648b92018-01-04 17:39:15 -05001948 if(member1.name != member2.name)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001949 {
Alexis Hetubc648b92018-01-04 17:39:15 -05001950 appendToInfoLog("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')",
1951 blockMemberIndex, block1.name.c_str(), member1.name.c_str(), member2.name.c_str());
1952 return false;
1953 }
1954 if(member1.arraySize != member2.arraySize)
1955 {
1956 appendToInfoLog("Array sizes for %s differ between vertex and fragment shaders", member1.name.c_str());
1957 return false;
1958 }
1959 if(member1.precision != member2.precision)
1960 {
1961 appendToInfoLog("Precisions for %s differ between vertex and fragment shaders", member1.name.c_str());
1962 return false;
1963 }
1964 if(member1.type != member2.type)
1965 {
1966 appendToInfoLog("Types for %s differ between vertex and fragment shaders", member1.name.c_str());
1967 return false;
1968 }
1969 if(member1.blockInfo.isRowMajorMatrix != member2.blockInfo.isRowMajorMatrix)
1970 {
1971 appendToInfoLog("Matrix packings for %s differ between vertex and fragment shaders", member1.name.c_str());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001972 return false;
1973 }
1974 }
1975 return true;
1976 }
1977
Alexis Hetu924513c2018-01-05 15:48:12 -05001978 bool Program::areMatchingFields(const std::vector<glsl::ShaderVariable>& fields1, const std::vector<glsl::ShaderVariable>& fields2, const std::string& name)
1979 {
1980 if(fields1.size() != fields2.size())
1981 {
1982 appendToInfoLog("Structure lengths for %s differ between vertex and fragment shaders", name.c_str());
1983 return false;
1984 }
1985
Alexis Hetuc67e57e2018-01-09 16:44:59 -05001986 for(size_t i = 0; i < fields1.size(); ++i)
Alexis Hetu924513c2018-01-05 15:48:12 -05001987 {
1988 if(fields1[i].name != fields2[i].name)
1989 {
1990 appendToInfoLog("Name mismatch for field '%d' of %s: ('%s', '%s')",
1991 i, name.c_str(), fields1[i].name.c_str(), fields2[i].name.c_str());
1992 return false;
1993 }
1994 if(fields1[i].type != fields2[i].type)
1995 {
1996 appendToInfoLog("Type for %s.%s differ between vertex and fragment shaders", name.c_str(), fields1[i].name.c_str());
1997 return false;
1998 }
1999 if(fields1[i].arraySize != fields2[i].arraySize)
2000 {
2001 appendToInfoLog("Array size for %s.%s differ between vertex and fragment shaders", name.c_str(), fields1[i].name.c_str());
2002 return false;
2003 }
2004 if(!areMatchingFields(fields1[i].fields, fields2[i].fields, fields1[i].name))
2005 {
2006 return false;
2007 }
2008 }
2009
2010 return true;
2011 }
2012
Nicolas Capens0bac2852016-05-07 06:09:58 -04002013 bool Program::linkUniformBlocks(const Shader *vertexShader, const Shader *fragmentShader)
2014 {
2015 const glsl::ActiveUniformBlocks &vertexUniformBlocks = vertexShader->activeUniformBlocks;
2016 const glsl::ActiveUniformBlocks &fragmentUniformBlocks = fragmentShader->activeUniformBlocks;
2017 // Check that interface blocks defined in the vertex and fragment shaders are identical
2018 typedef std::map<std::string, const glsl::UniformBlock*> UniformBlockMap;
2019 UniformBlockMap linkedUniformBlocks;
2020 for(unsigned int blockIndex = 0; blockIndex < vertexUniformBlocks.size(); blockIndex++)
2021 {
2022 const glsl::UniformBlock &vertexUniformBlock = vertexUniformBlocks[blockIndex];
2023 linkedUniformBlocks[vertexUniformBlock.name] = &vertexUniformBlock;
2024 }
2025 for(unsigned int blockIndex = 0; blockIndex < fragmentUniformBlocks.size(); blockIndex++)
2026 {
2027 const glsl::UniformBlock &fragmentUniformBlock = fragmentUniformBlocks[blockIndex];
2028 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentUniformBlock.name);
2029 if(entry != linkedUniformBlocks.end())
2030 {
2031 const glsl::UniformBlock &vertexUniformBlock = *entry->second;
2032 if(!areMatchingUniformBlocks(vertexUniformBlock, fragmentUniformBlock, vertexShader, fragmentShader))
2033 {
2034 return false;
2035 }
2036 }
2037 }
2038 for(unsigned int blockIndex = 0; blockIndex < vertexUniformBlocks.size(); blockIndex++)
2039 {
2040 const glsl::UniformBlock &uniformBlock = vertexUniformBlocks[blockIndex];
2041 if(!defineUniformBlock(vertexShader, uniformBlock))
2042 {
2043 return false;
2044 }
2045 }
2046 for(unsigned int blockIndex = 0; blockIndex < fragmentUniformBlocks.size(); blockIndex++)
2047 {
2048 const glsl::UniformBlock &uniformBlock = fragmentUniformBlocks[blockIndex];
2049 if(!defineUniformBlock(fragmentShader, uniformBlock))
2050 {
2051 return false;
2052 }
2053 }
2054 return true;
2055 }
2056
2057 bool Program::defineUniformBlock(const Shader *shader, const glsl::UniformBlock &block)
2058 {
2059 GLuint blockIndex = getUniformBlockIndex(block.name);
2060
2061 if(blockIndex == GL_INVALID_INDEX)
2062 {
2063 const std::vector<int>& fields = block.fields;
2064 std::vector<unsigned int> memberUniformIndexes;
2065 for(size_t i = 0; i < fields.size(); ++i)
2066 {
2067 memberUniformIndexes.push_back(fields[i]);
2068 }
2069
2070 if(block.arraySize > 0)
2071 {
2072 int regIndex = block.registerIndex;
2073 int regInc = block.dataSize / (glsl::BlockLayoutEncoder::BytesPerComponent * glsl::BlockLayoutEncoder::ComponentsPerRegister);
2074 for(unsigned int i = 0; i < block.arraySize; ++i, regIndex += regInc)
2075 {
2076 uniformBlocks.push_back(new UniformBlock(block.name, i, block.dataSize, memberUniformIndexes));
2077 uniformBlocks[uniformBlocks.size() - 1]->setRegisterIndex(shader->getType(), regIndex);
2078 }
2079 }
2080 else
2081 {
2082 uniformBlocks.push_back(new UniformBlock(block.name, GL_INVALID_INDEX, block.dataSize, memberUniformIndexes));
2083 uniformBlocks[uniformBlocks.size() - 1]->setRegisterIndex(shader->getType(), block.registerIndex);
2084 }
2085 }
2086 else
2087 {
2088 int regIndex = block.registerIndex;
2089 int regInc = block.dataSize / (glsl::BlockLayoutEncoder::BytesPerComponent * glsl::BlockLayoutEncoder::ComponentsPerRegister);
2090 int nbBlocks = (block.arraySize > 0) ? block.arraySize : 1;
2091 for(int i = 0; i < nbBlocks; ++i, regIndex += regInc)
2092 {
2093 uniformBlocks[blockIndex + i]->setRegisterIndex(shader->getType(), regIndex);
2094 }
2095 }
2096
2097 return true;
2098 }
2099
Ben Vanik1fd3b282017-07-10 14:08:12 -07002100 bool Program::applyUniform(Device *device, GLint location, float* data)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002101 {
2102 Uniform *targetUniform = uniforms[uniformIndex[location].index];
2103
2104 if(targetUniform->psRegisterIndex != -1)
2105 {
2106 device->setPixelShaderConstantF(targetUniform->psRegisterIndex, data, targetUniform->registerCount());
2107 }
2108
2109 if(targetUniform->vsRegisterIndex != -1)
2110 {
2111 device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, data, targetUniform->registerCount());
2112 }
2113
2114 return true;
2115 }
2116
Ben Vanik1fd3b282017-07-10 14:08:12 -07002117 bool Program::applyUniform1bv(Device *device, GLint location, GLsizei count, const GLboolean *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002118 {
2119 int vector[MAX_UNIFORM_VECTORS][4];
2120
2121 for(int i = 0; i < count; i++)
2122 {
2123 vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2124 vector[i][1] = 0;
2125 vector[i][2] = 0;
2126 vector[i][3] = 0;
2127
2128 v += 1;
2129 }
2130
Ben Vanik1fd3b282017-07-10 14:08:12 -07002131 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002132 }
2133
Ben Vanik1fd3b282017-07-10 14:08:12 -07002134 bool Program::applyUniform2bv(Device *device, GLint location, GLsizei count, const GLboolean *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002135 {
2136 int vector[MAX_UNIFORM_VECTORS][4];
2137
2138 for(int i = 0; i < count; i++)
2139 {
2140 vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2141 vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2142 vector[i][2] = 0;
2143 vector[i][3] = 0;
2144
2145 v += 2;
2146 }
2147
Ben Vanik1fd3b282017-07-10 14:08:12 -07002148 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002149 }
2150
Ben Vanik1fd3b282017-07-10 14:08:12 -07002151 bool Program::applyUniform3bv(Device *device, GLint location, GLsizei count, const GLboolean *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002152 {
2153 int vector[MAX_UNIFORM_VECTORS][4];
2154
2155 for(int i = 0; i < count; i++)
2156 {
2157 vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2158 vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2159 vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2160 vector[i][3] = 0;
2161
2162 v += 3;
2163 }
2164
Ben Vanik1fd3b282017-07-10 14:08:12 -07002165 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002166 }
2167
Ben Vanik1fd3b282017-07-10 14:08:12 -07002168 bool Program::applyUniform4bv(Device *device, GLint location, GLsizei count, const GLboolean *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002169 {
2170 int vector[MAX_UNIFORM_VECTORS][4];
2171
2172 for(int i = 0; i < count; i++)
2173 {
2174 vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2175 vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2176 vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2177 vector[i][3] = (v[3] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
2178
2179 v += 4;
2180 }
2181
Ben Vanik1fd3b282017-07-10 14:08:12 -07002182 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002183 }
2184
Ben Vanik1fd3b282017-07-10 14:08:12 -07002185 bool Program::applyUniform1fv(Device *device, GLint location, GLsizei count, const GLfloat *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002186 {
2187 float vector[MAX_UNIFORM_VECTORS][4];
2188
2189 for(int i = 0; i < count; i++)
2190 {
2191 vector[i][0] = v[0];
2192 vector[i][1] = 0;
2193 vector[i][2] = 0;
2194 vector[i][3] = 0;
2195
2196 v += 1;
2197 }
2198
Ben Vanik1fd3b282017-07-10 14:08:12 -07002199 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002200 }
2201
Ben Vanik1fd3b282017-07-10 14:08:12 -07002202 bool Program::applyUniform2fv(Device *device, GLint location, GLsizei count, const GLfloat *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002203 {
2204 float vector[MAX_UNIFORM_VECTORS][4];
2205
2206 for(int i = 0; i < count; i++)
2207 {
2208 vector[i][0] = v[0];
2209 vector[i][1] = v[1];
2210 vector[i][2] = 0;
2211 vector[i][3] = 0;
2212
2213 v += 2;
2214 }
2215
Ben Vanik1fd3b282017-07-10 14:08:12 -07002216 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002217 }
2218
Ben Vanik1fd3b282017-07-10 14:08:12 -07002219 bool Program::applyUniform3fv(Device *device, GLint location, GLsizei count, const GLfloat *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002220 {
2221 float vector[MAX_UNIFORM_VECTORS][4];
2222
2223 for(int i = 0; i < count; i++)
2224 {
2225 vector[i][0] = v[0];
2226 vector[i][1] = v[1];
2227 vector[i][2] = v[2];
2228 vector[i][3] = 0;
2229
2230 v += 3;
2231 }
2232
Ben Vanik1fd3b282017-07-10 14:08:12 -07002233 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002234 }
2235
Ben Vanik1fd3b282017-07-10 14:08:12 -07002236 bool Program::applyUniform4fv(Device *device, GLint location, GLsizei count, const GLfloat *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002237 {
Ben Vanik1fd3b282017-07-10 14:08:12 -07002238 return applyUniform(device, location, (float*)v);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002239 }
2240
Ben Vanik1fd3b282017-07-10 14:08:12 -07002241 bool Program::applyUniformMatrix2fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002242 {
2243 float matrix[(MAX_UNIFORM_VECTORS + 1) / 2][2][4];
2244
2245 for(int i = 0; i < count; i++)
2246 {
2247 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = 0; matrix[i][0][3] = 0;
2248 matrix[i][1][0] = value[2]; matrix[i][1][1] = value[3]; matrix[i][1][2] = 0; matrix[i][1][3] = 0;
2249
2250 value += 4;
2251 }
2252
Ben Vanik1fd3b282017-07-10 14:08:12 -07002253 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002254 }
2255
Ben Vanik1fd3b282017-07-10 14:08:12 -07002256 bool Program::applyUniformMatrix2x3fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002257 {
2258 float matrix[(MAX_UNIFORM_VECTORS + 1) / 2][2][4];
2259
2260 for(int i = 0; i < count; i++)
2261 {
2262 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = value[2]; matrix[i][0][3] = 0;
2263 matrix[i][1][0] = value[3]; matrix[i][1][1] = value[4]; matrix[i][1][2] = value[5]; matrix[i][1][3] = 0;
2264
2265 value += 6;
2266 }
2267
Ben Vanik1fd3b282017-07-10 14:08:12 -07002268 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002269 }
2270
Ben Vanik1fd3b282017-07-10 14:08:12 -07002271 bool Program::applyUniformMatrix2x4fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002272 {
2273 float matrix[(MAX_UNIFORM_VECTORS + 1) / 2][2][4];
2274
2275 for(int i = 0; i < count; i++)
2276 {
2277 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = value[2]; matrix[i][0][3] = value[3];
2278 matrix[i][1][0] = value[4]; matrix[i][1][1] = value[5]; matrix[i][1][2] = value[6]; matrix[i][1][3] = value[7];
2279
2280 value += 8;
2281 }
2282
Ben Vanik1fd3b282017-07-10 14:08:12 -07002283 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002284 }
2285
Ben Vanik1fd3b282017-07-10 14:08:12 -07002286 bool Program::applyUniformMatrix3fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002287 {
2288 float matrix[(MAX_UNIFORM_VECTORS + 2) / 3][3][4];
2289
2290 for(int i = 0; i < count; i++)
2291 {
2292 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = value[2]; matrix[i][0][3] = 0;
2293 matrix[i][1][0] = value[3]; matrix[i][1][1] = value[4]; matrix[i][1][2] = value[5]; matrix[i][1][3] = 0;
2294 matrix[i][2][0] = value[6]; matrix[i][2][1] = value[7]; matrix[i][2][2] = value[8]; matrix[i][2][3] = 0;
2295
2296 value += 9;
2297 }
2298
Ben Vanik1fd3b282017-07-10 14:08:12 -07002299 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002300 }
2301
Ben Vanik1fd3b282017-07-10 14:08:12 -07002302 bool Program::applyUniformMatrix3x2fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002303 {
2304 float matrix[(MAX_UNIFORM_VECTORS + 2) / 3][3][4];
2305
2306 for(int i = 0; i < count; i++)
2307 {
2308 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = 0; matrix[i][0][3] = 0;
2309 matrix[i][1][0] = value[2]; matrix[i][1][1] = value[3]; matrix[i][1][2] = 0; matrix[i][1][3] = 0;
2310 matrix[i][2][0] = value[4]; matrix[i][2][1] = value[5]; matrix[i][2][2] = 0; matrix[i][2][3] = 0;
2311
2312 value += 6;
2313 }
2314
Ben Vanik1fd3b282017-07-10 14:08:12 -07002315 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002316 }
2317
Ben Vanik1fd3b282017-07-10 14:08:12 -07002318 bool Program::applyUniformMatrix3x4fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002319 {
2320 float matrix[(MAX_UNIFORM_VECTORS + 2) / 3][3][4];
2321
2322 for(int i = 0; i < count; i++)
2323 {
2324 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = value[2]; matrix[i][0][3] = value[3];
2325 matrix[i][1][0] = value[4]; matrix[i][1][1] = value[5]; matrix[i][1][2] = value[6]; matrix[i][1][3] = value[7];
2326 matrix[i][2][0] = value[8]; matrix[i][2][1] = value[9]; matrix[i][2][2] = value[10]; matrix[i][2][3] = value[11];
2327
2328 value += 12;
2329 }
2330
Ben Vanik1fd3b282017-07-10 14:08:12 -07002331 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002332 }
2333
Ben Vanik1fd3b282017-07-10 14:08:12 -07002334 bool Program::applyUniformMatrix4fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002335 {
Ben Vanik1fd3b282017-07-10 14:08:12 -07002336 return applyUniform(device, location, (float*)value);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002337 }
2338
Ben Vanik1fd3b282017-07-10 14:08:12 -07002339 bool Program::applyUniformMatrix4x2fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002340 {
2341 float matrix[(MAX_UNIFORM_VECTORS + 3) / 4][4][4];
2342
2343 for(int i = 0; i < count; i++)
2344 {
2345 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = 0; matrix[i][0][3] = 0;
2346 matrix[i][1][0] = value[2]; matrix[i][1][1] = value[3]; matrix[i][1][2] = 0; matrix[i][1][3] = 0;
2347 matrix[i][2][0] = value[4]; matrix[i][2][1] = value[5]; matrix[i][2][2] = 0; matrix[i][2][3] = 0;
2348 matrix[i][3][0] = value[6]; matrix[i][3][1] = value[7]; matrix[i][3][2] = 0; matrix[i][3][3] = 0;
2349
2350 value += 8;
2351 }
2352
Ben Vanik1fd3b282017-07-10 14:08:12 -07002353 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002354 }
2355
Ben Vanik1fd3b282017-07-10 14:08:12 -07002356 bool Program::applyUniformMatrix4x3fv(Device *device, GLint location, GLsizei count, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002357 {
2358 float matrix[(MAX_UNIFORM_VECTORS + 3) / 4][4][4];
2359
2360 for(int i = 0; i < count; i++)
2361 {
2362 matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = value[2]; matrix[i][0][3] = 0;
2363 matrix[i][1][0] = value[3]; matrix[i][1][1] = value[4]; matrix[i][1][2] = value[5]; matrix[i][1][3] = 0;
2364 matrix[i][2][0] = value[6]; matrix[i][2][1] = value[7]; matrix[i][2][2] = value[8]; matrix[i][2][3] = 0;
2365 matrix[i][3][0] = value[9]; matrix[i][3][1] = value[10]; matrix[i][3][2] = value[11]; matrix[i][3][3] = 0;
2366
2367 value += 12;
2368 }
2369
Ben Vanik1fd3b282017-07-10 14:08:12 -07002370 return applyUniform(device, location, (float*)matrix);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002371 }
2372
Ben Vanik1fd3b282017-07-10 14:08:12 -07002373 bool Program::applyUniform1iv(Device *device, GLint location, GLsizei count, const GLint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002374 {
2375 GLint vector[MAX_UNIFORM_VECTORS][4];
2376
2377 for(int i = 0; i < count; i++)
2378 {
2379 vector[i][0] = v[i];
2380 vector[i][1] = 0;
2381 vector[i][2] = 0;
2382 vector[i][3] = 0;
2383 }
2384
2385 Uniform *targetUniform = uniforms[uniformIndex[location].index];
2386 if(IsSamplerUniform(targetUniform->type))
2387 {
2388 if(targetUniform->psRegisterIndex != -1)
2389 {
2390 for(int i = 0; i < count; i++)
2391 {
2392 unsigned int samplerIndex = targetUniform->psRegisterIndex + i;
2393
Alexis Hétu2cd00092018-01-03 13:04:09 +00002394 if(samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002395 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002396 ASSERT(samplersPS[samplerIndex].active);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002397 samplersPS[samplerIndex].logicalTextureUnit = v[i];
2398 }
2399 }
2400 }
2401
2402 if(targetUniform->vsRegisterIndex != -1)
2403 {
2404 for(int i = 0; i < count; i++)
2405 {
2406 unsigned int samplerIndex = targetUniform->vsRegisterIndex + i;
2407
Alexis Hétu2cd00092018-01-03 13:04:09 +00002408 if(samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002409 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002410 ASSERT(samplersVS[samplerIndex].active);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002411 samplersVS[samplerIndex].logicalTextureUnit = v[i];
2412 }
2413 }
2414 }
2415 }
2416 else
2417 {
Ben Vanik1fd3b282017-07-10 14:08:12 -07002418 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002419 }
2420
2421 return true;
2422 }
2423
Ben Vanik1fd3b282017-07-10 14:08:12 -07002424 bool Program::applyUniform2iv(Device *device, GLint location, GLsizei count, const GLint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002425 {
2426 GLint vector[MAX_UNIFORM_VECTORS][4];
2427
2428 for(int i = 0; i < count; i++)
2429 {
2430 vector[i][0] = v[0];
2431 vector[i][1] = v[1];
2432 vector[i][2] = 0;
2433 vector[i][3] = 0;
2434
2435 v += 2;
2436 }
2437
Ben Vanik1fd3b282017-07-10 14:08:12 -07002438 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002439 }
2440
Ben Vanik1fd3b282017-07-10 14:08:12 -07002441 bool Program::applyUniform3iv(Device *device, GLint location, GLsizei count, const GLint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002442 {
2443 GLint vector[MAX_UNIFORM_VECTORS][4];
2444
2445 for(int i = 0; i < count; i++)
2446 {
2447 vector[i][0] = v[0];
2448 vector[i][1] = v[1];
2449 vector[i][2] = v[2];
2450 vector[i][3] = 0;
2451
2452 v += 3;
2453 }
2454
Ben Vanik1fd3b282017-07-10 14:08:12 -07002455 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002456 }
2457
Ben Vanik1fd3b282017-07-10 14:08:12 -07002458 bool Program::applyUniform4iv(Device *device, GLint location, GLsizei count, const GLint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002459 {
2460 GLint vector[MAX_UNIFORM_VECTORS][4];
2461
2462 for(int i = 0; i < count; i++)
2463 {
2464 vector[i][0] = v[0];
2465 vector[i][1] = v[1];
2466 vector[i][2] = v[2];
2467 vector[i][3] = v[3];
2468
2469 v += 4;
2470 }
2471
Ben Vanik1fd3b282017-07-10 14:08:12 -07002472 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002473 }
2474
Ben Vanik1fd3b282017-07-10 14:08:12 -07002475 bool Program::applyUniform1uiv(Device *device, GLint location, GLsizei count, const GLuint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002476 {
2477 GLuint vector[MAX_UNIFORM_VECTORS][4];
2478
2479 for(int i = 0; i < count; i++)
2480 {
2481 vector[i][0] = v[i];
2482 vector[i][1] = 0;
2483 vector[i][2] = 0;
2484 vector[i][3] = 0;
2485 }
2486
2487 Uniform *targetUniform = uniforms[uniformIndex[location].index];
2488 if(IsSamplerUniform(targetUniform->type))
2489 {
2490 if(targetUniform->psRegisterIndex != -1)
2491 {
2492 for(int i = 0; i < count; i++)
2493 {
2494 unsigned int samplerIndex = targetUniform->psRegisterIndex + i;
2495
Alexis Hétu2cd00092018-01-03 13:04:09 +00002496 if(samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002497 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002498 ASSERT(samplersPS[samplerIndex].active);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002499 samplersPS[samplerIndex].logicalTextureUnit = v[i];
2500 }
2501 }
2502 }
2503
2504 if(targetUniform->vsRegisterIndex != -1)
2505 {
2506 for(int i = 0; i < count; i++)
2507 {
2508 unsigned int samplerIndex = targetUniform->vsRegisterIndex + i;
2509
Alexis Hétu2cd00092018-01-03 13:04:09 +00002510 if(samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002511 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00002512 ASSERT(samplersVS[samplerIndex].active);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002513 samplersVS[samplerIndex].logicalTextureUnit = v[i];
2514 }
2515 }
2516 }
2517 }
2518 else
2519 {
Ben Vanik1fd3b282017-07-10 14:08:12 -07002520 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002521 }
2522
2523 return true;
2524 }
2525
Ben Vanik1fd3b282017-07-10 14:08:12 -07002526 bool Program::applyUniform2uiv(Device *device, GLint location, GLsizei count, const GLuint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002527 {
2528 GLuint vector[MAX_UNIFORM_VECTORS][4];
2529
2530 for(int i = 0; i < count; i++)
2531 {
2532 vector[i][0] = v[0];
2533 vector[i][1] = v[1];
2534 vector[i][2] = 0;
2535 vector[i][3] = 0;
2536
2537 v += 2;
2538 }
2539
Ben Vanik1fd3b282017-07-10 14:08:12 -07002540 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002541 }
2542
Ben Vanik1fd3b282017-07-10 14:08:12 -07002543 bool Program::applyUniform3uiv(Device *device, GLint location, GLsizei count, const GLuint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002544 {
2545 GLuint vector[MAX_UNIFORM_VECTORS][4];
2546
2547 for(int i = 0; i < count; i++)
2548 {
2549 vector[i][0] = v[0];
2550 vector[i][1] = v[1];
2551 vector[i][2] = v[2];
2552 vector[i][3] = 0;
2553
2554 v += 3;
2555 }
2556
Ben Vanik1fd3b282017-07-10 14:08:12 -07002557 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002558 }
2559
Ben Vanik1fd3b282017-07-10 14:08:12 -07002560 bool Program::applyUniform4uiv(Device *device, GLint location, GLsizei count, const GLuint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002561 {
2562 GLuint vector[MAX_UNIFORM_VECTORS][4];
2563
2564 for(int i = 0; i < count; i++)
2565 {
2566 vector[i][0] = v[0];
2567 vector[i][1] = v[1];
2568 vector[i][2] = v[2];
2569 vector[i][3] = v[3];
2570
2571 v += 4;
2572 }
2573
Ben Vanik1fd3b282017-07-10 14:08:12 -07002574 return applyUniform(device, location, (float*)vector);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002575 }
2576
2577 void Program::appendToInfoLog(const char *format, ...)
2578 {
2579 if(!format)
2580 {
2581 return;
2582 }
2583
2584 char info[1024];
2585
2586 va_list vararg;
2587 va_start(vararg, format);
2588 vsnprintf(info, sizeof(info), format, vararg);
2589 va_end(vararg);
2590
2591 size_t infoLength = strlen(info);
2592
2593 if(!infoLog)
2594 {
2595 infoLog = new char[infoLength + 2];
2596 strcpy(infoLog, info);
2597 strcpy(infoLog + infoLength, "\n");
2598 }
2599 else
2600 {
2601 size_t logLength = strlen(infoLog);
2602 char *newLog = new char[logLength + infoLength + 2];
2603 strcpy(newLog, infoLog);
2604 strcpy(newLog + logLength, info);
2605 strcpy(newLog + logLength + infoLength, "\n");
2606
2607 delete[] infoLog;
2608 infoLog = newLog;
2609 }
2610 }
2611
2612 void Program::resetInfoLog()
2613 {
2614 if(infoLog)
2615 {
2616 delete[] infoLog;
2617 infoLog = 0;
2618 }
2619 }
2620
2621 // Returns the program object to an unlinked state, before re-linking, or at destruction
2622 void Program::unlink()
2623 {
2624 delete vertexBinary;
2625 vertexBinary = 0;
2626 delete pixelBinary;
2627 pixelBinary = 0;
2628
Alexis Hetu23f54d72017-12-05 16:03:51 -05002629 linkedAttribute.clear();
2630 linkedAttributeLocation.clear();
2631
Nicolas Capens0bac2852016-05-07 06:09:58 -04002632 for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
2633 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04002634 attributeStream[index] = -1;
2635 }
2636
Alexis Hétu2cd00092018-01-03 13:04:09 +00002637 for(int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2638 {
2639 samplersPS[index].active = false;
2640 }
2641
2642 for(int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
2643 {
2644 samplersVS[index].active = false;
2645 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002646
2647 while(!uniforms.empty())
2648 {
2649 delete uniforms.back();
2650 uniforms.pop_back();
2651 }
2652
2653 while(!uniformBlocks.empty())
2654 {
2655 delete uniformBlocks.back();
2656 uniformBlocks.pop_back();
2657 }
2658
2659 uniformIndex.clear();
2660 transformFeedbackLinkedVaryings.clear();
2661
2662 delete[] infoLog;
2663 infoLog = 0;
2664
2665 linked = false;
2666 }
2667
2668 bool Program::isLinked() const
2669 {
2670 return linked;
2671 }
2672
2673 bool Program::isValidated() const
2674 {
2675 return validated;
2676 }
2677
2678 GLint Program::getBinaryLength() const
2679 {
2680 UNIMPLEMENTED();
2681 return 0;
2682 }
2683
2684 void Program::release()
2685 {
2686 referenceCount--;
2687
2688 if(referenceCount == 0 && orphaned)
2689 {
2690 resourceManager->deleteProgram(handle);
2691 }
2692 }
2693
2694 void Program::addRef()
2695 {
2696 referenceCount++;
2697 }
2698
2699 unsigned int Program::getRefCount() const
2700 {
2701 return referenceCount;
2702 }
2703
2704 unsigned int Program::getSerial() const
2705 {
2706 return serial;
2707 }
2708
2709 unsigned int Program::issueSerial()
2710 {
2711 return currentSerial++;
2712 }
2713
2714 size_t Program::getInfoLogLength() const
2715 {
2716 if(!infoLog)
2717 {
2718 return 0;
2719 }
2720 else
2721 {
2722 return strlen(infoLog) + 1;
2723 }
2724 }
2725
2726 void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *buffer)
2727 {
2728 int index = 0;
2729
2730 if(bufSize > 0)
2731 {
2732 if(infoLog)
2733 {
2734 index = std::min(bufSize - 1, (int)strlen(infoLog));
2735 memcpy(buffer, infoLog, index);
2736 }
2737
2738 buffer[index] = '\0';
2739 }
2740
2741 if(length)
2742 {
2743 *length = index;
2744 }
2745 }
2746
2747 void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2748 {
2749 int total = 0;
2750
2751 if(vertexShader && (total < maxCount))
2752 {
2753 shaders[total++] = vertexShader->getName();
2754 }
2755
2756 if(fragmentShader && (total < maxCount))
2757 {
2758 shaders[total++] = fragmentShader->getName();
2759 }
2760
2761 if(count)
2762 {
2763 *count = total;
2764 }
2765 }
2766
2767 void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
2768 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05002769 ASSERT(index < linkedAttribute.size());
Nicolas Capens0bac2852016-05-07 06:09:58 -04002770
Alexis Hetu23f54d72017-12-05 16:03:51 -05002771 std::vector<glsl::Attribute>::const_iterator it = linkedAttribute.begin() + index;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002772
2773 if(bufsize > 0)
2774 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05002775 const char *string = it->name.c_str();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002776
2777 strncpy(name, string, 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 *size = 1; // Always a single 'type' instance
2787
Alexis Hetu23f54d72017-12-05 16:03:51 -05002788 *type = it->type;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002789 }
2790
2791 size_t Program::getActiveAttributeCount() const
2792 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05002793 return linkedAttribute.size();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002794 }
2795
2796 GLint Program::getActiveAttributeMaxLength() const
2797 {
2798 int maxLength = 0;
2799
Alexis Hetu23f54d72017-12-05 16:03:51 -05002800 std::vector<glsl::Attribute>::const_iterator it = linkedAttribute.begin();
2801 std::vector<glsl::Attribute>::const_iterator itEnd = linkedAttribute.end();
2802 for(; it != itEnd; ++it)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002803 {
Alexis Hetu23f54d72017-12-05 16:03:51 -05002804 maxLength = std::max((int)(it->name.length() + 1), maxLength);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002805 }
2806
2807 return maxLength;
2808 }
2809
2810 void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
2811 {
2812 if(bufsize > 0)
2813 {
2814 std::string string = uniforms[index]->name;
2815
2816 if(uniforms[index]->isArray())
2817 {
2818 string += "[0]";
2819 }
2820
2821 strncpy(name, string.c_str(), bufsize);
2822 name[bufsize - 1] = '\0';
2823
2824 if(length)
2825 {
Alexis Hetu05c32b92016-06-23 11:32:07 -04002826 *length = static_cast<GLsizei>(strlen(name));
Nicolas Capens0bac2852016-05-07 06:09:58 -04002827 }
2828 }
2829
2830 *size = uniforms[index]->size();
2831
2832 *type = uniforms[index]->type;
2833 }
2834
2835 size_t Program::getActiveUniformCount() const
2836 {
2837 return uniforms.size();
2838 }
2839
2840 GLint Program::getActiveUniformMaxLength() const
2841 {
2842 int maxLength = 0;
2843
2844 size_t numUniforms = uniforms.size();
2845 for(size_t uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2846 {
2847 if(!uniforms[uniformIndex]->name.empty())
2848 {
2849 int length = (int)(uniforms[uniformIndex]->name.length() + 1);
2850 if(uniforms[uniformIndex]->isArray())
2851 {
2852 length += 3; // Counting in "[0]".
2853 }
2854 maxLength = std::max(length, maxLength);
2855 }
2856 }
2857
2858 return maxLength;
2859 }
2860
2861 GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
2862 {
2863 const Uniform& uniform = *uniforms[index];
2864 switch(pname)
2865 {
2866 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2867 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.size());
2868 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
2869 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockInfo.index;
2870 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2871 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2872 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2873 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
2874 default:
2875 UNREACHABLE(pname);
2876 break;
2877 }
2878 return 0;
2879 }
2880
2881 void Program::getActiveUniformBlockName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const
2882 {
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04002883 ASSERT(index < getActiveUniformBlockCount());
Nicolas Capens0bac2852016-05-07 06:09:58 -04002884
2885 const UniformBlock &uniformBlock = *uniformBlocks[index];
2886
2887 if(bufSize > 0)
2888 {
2889 std::string string = uniformBlock.name;
2890
2891 if(uniformBlock.isArrayElement())
2892 {
2893 std::ostringstream elementIndex;
2894 elementIndex << uniformBlock.elementIndex;
2895 string += "[" + elementIndex.str() + "]";
2896 }
2897
2898 strncpy(name, string.c_str(), bufSize);
2899 name[bufSize - 1] = '\0';
2900
2901 if(length)
2902 {
Alexis Hetu05c32b92016-06-23 11:32:07 -04002903 *length = static_cast<GLsizei>(strlen(name));
Nicolas Capens0bac2852016-05-07 06:09:58 -04002904 }
2905 }
2906 }
2907
2908 size_t Program::getActiveUniformBlockCount() const
2909 {
2910 return uniformBlocks.size();
2911 }
2912
2913 GLint Program::getActiveUniformBlockMaxLength() const
2914 {
Alexis Hetu05c32b92016-06-23 11:32:07 -04002915 GLint maxLength = 0;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002916
2917 if(isLinked())
2918 {
2919 size_t numUniformBlocks = getActiveUniformBlockCount();
2920 for(size_t uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2921 {
2922 const UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];
2923 if(!uniformBlock.name.empty())
2924 {
Alexis Hetu05c32b92016-06-23 11:32:07 -04002925 GLint length = static_cast<GLint>(uniformBlock.name.length() + 1);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002926
2927 // Counting in "[0]".
Alexis Hetu05c32b92016-06-23 11:32:07 -04002928 const GLint arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002929
2930 maxLength = std::max(length + arrayLength, maxLength);
2931 }
2932 }
2933 }
2934
2935 return maxLength;
2936 }
2937
2938 void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
2939 {
2940 transformFeedbackVaryings.resize(count);
2941 for(GLsizei i = 0; i < count; i++)
2942 {
2943 transformFeedbackVaryings[i] = varyings[i];
2944 }
2945
2946 transformFeedbackBufferMode = bufferMode;
2947 }
2948
2949 void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
2950 {
2951 if(linked)
2952 {
2953 ASSERT(index < transformFeedbackLinkedVaryings.size());
2954 const LinkedVarying &varying = transformFeedbackLinkedVaryings[index];
2955 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
2956 if(length)
2957 {
2958 *length = lastNameIdx;
2959 }
2960 if(size)
2961 {
2962 *size = varying.size;
2963 }
2964 if(type)
2965 {
2966 *type = varying.type;
2967 }
2968 if(name)
2969 {
2970 memcpy(name, varying.name.c_str(), lastNameIdx);
2971 name[lastNameIdx] = '\0';
2972 }
2973 }
2974 }
2975
2976 GLsizei Program::getTransformFeedbackVaryingCount() const
2977 {
2978 if(linked)
2979 {
2980 return static_cast<GLsizei>(transformFeedbackLinkedVaryings.size());
2981 }
2982 else
2983 {
2984 return 0;
2985 }
2986 }
2987
2988 GLsizei Program::getTransformFeedbackVaryingMaxLength() const
2989 {
2990 if(linked)
2991 {
2992 GLsizei maxSize = 0;
2993 for(size_t i = 0; i < transformFeedbackLinkedVaryings.size(); i++)
2994 {
2995 const LinkedVarying &varying = transformFeedbackLinkedVaryings[i];
2996 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
2997 }
2998
2999 return maxSize;
3000 }
3001 else
3002 {
3003 return 0;
3004 }
3005 }
3006
3007 GLenum Program::getTransformFeedbackBufferMode() const
3008 {
3009 return transformFeedbackBufferMode;
3010 }
3011
3012 void Program::flagForDeletion()
3013 {
3014 orphaned = true;
3015 }
3016
3017 bool Program::isFlaggedForDeletion() const
3018 {
3019 return orphaned;
3020 }
3021
Ben Vanik1fd3b282017-07-10 14:08:12 -07003022 void Program::validate(Device* device)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003023 {
3024 resetInfoLog();
3025
3026 if(!isLinked())
3027 {
3028 appendToInfoLog("Program has not been successfully linked.");
3029 validated = false;
3030 }
3031 else
3032 {
Ben Vanik1fd3b282017-07-10 14:08:12 -07003033 applyUniforms(device);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003034 if(!validateSamplers(true))
3035 {
3036 validated = false;
3037 }
3038 else
3039 {
3040 validated = true;
3041 }
3042 }
3043 }
3044
3045 bool Program::validateSamplers(bool logErrors)
3046 {
3047 // if any two active samplers in a program are of different types, but refer to the same
3048 // texture image unit, and this is the current program, then ValidateProgram will fail, and
3049 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
3050
3051 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
3052
3053 for(unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS; i++)
3054 {
3055 textureUnitType[i] = TEXTURE_UNKNOWN;
3056 }
3057
Alexis Hétu2cd00092018-01-03 13:04:09 +00003058 for(unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003059 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00003060 if(samplersPS[i].active)
Alexis Hetua141a072017-12-20 14:49:37 -05003061 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00003062 unsigned int unit = samplersPS[i].logicalTextureUnit;
Alexis Hetua141a072017-12-20 14:49:37 -05003063
Alexis Hétu2cd00092018-01-03 13:04:09 +00003064 if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003065 {
3066 if(logErrors)
3067 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00003068 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003069 }
3070
3071 return false;
3072 }
Alexis Hétu2cd00092018-01-03 13:04:09 +00003073
3074 if(textureUnitType[unit] != TEXTURE_UNKNOWN)
3075 {
3076 if(samplersPS[i].textureType != textureUnitType[unit])
3077 {
3078 if(logErrors)
3079 {
3080 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
3081 }
3082
3083 return false;
3084 }
3085 }
3086 else
3087 {
3088 textureUnitType[unit] = samplersPS[i].textureType;
3089 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003090 }
3091 }
3092
Alexis Hétu2cd00092018-01-03 13:04:09 +00003093 for(unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003094 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00003095 if(samplersVS[i].active)
Alexis Hetua141a072017-12-20 14:49:37 -05003096 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00003097 unsigned int unit = samplersVS[i].logicalTextureUnit;
Alexis Hetua141a072017-12-20 14:49:37 -05003098
Alexis Hétu2cd00092018-01-03 13:04:09 +00003099 if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003100 {
3101 if(logErrors)
3102 {
Alexis Hétu2cd00092018-01-03 13:04:09 +00003103 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003104 }
3105
3106 return false;
3107 }
Alexis Hétu2cd00092018-01-03 13:04:09 +00003108
3109 if(textureUnitType[unit] != TEXTURE_UNKNOWN)
3110 {
3111 if(samplersVS[i].textureType != textureUnitType[unit])
3112 {
3113 if(logErrors)
3114 {
3115 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
3116 }
3117
3118 return false;
3119 }
3120 }
3121 else
3122 {
3123 textureUnitType[unit] = samplersVS[i].textureType;
3124 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003125 }
3126 }
3127
3128 return true;
3129 }
3130}