1 /**
2  * Copyright (c) 2006-2019 LOVE Development Team
3  *
4  * This software is provided 'as-is', without any express or implied
5  * warranty.  In no event will the authors be held liable for any damages
6  * arising from the use of this software.
7  *
8  * Permission is granted to anyone to use this software for any purpose,
9  * including commercial applications, and to alter it and redistribute it
10  * freely, subject to the following restrictions:
11  *
12  * 1. The origin of this software must not be misrepresented; you must not
13  *    claim that you wrote the original software. If you use this software
14  *    in a product, an acknowledgment in the product documentation would be
15  *    appreciated but is not required.
16  * 2. Altered source versions must be plainly marked as such, and must not be
17  *    misrepresented as being the original software.
18  * 3. This notice may not be removed or altered from any source distribution.
19  **/
20 
21 // LOVE
22 #include "common/config.h"
23 
24 #include "Shader.h"
25 #include "Graphics.h"
26 
27 // C++
28 #include <algorithm>
29 #include <limits>
30 #include <sstream>
31 
32 namespace love
33 {
34 namespace graphics
35 {
36 namespace opengl
37 {
38 
Shader(love::graphics::ShaderStage * vertex,love::graphics::ShaderStage * pixel)39 Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel)
40 	: love::graphics::Shader(vertex, pixel)
41 	, program(0)
42 	, builtinUniforms()
43 	, builtinUniformInfo()
44 	, builtinAttributes()
45 	, canvasWasActive(false)
46 	, lastViewport()
47 	, lastPointSize(0.0f)
48 {
49 	// load shader source and create program object
50 	loadVolatile();
51 }
52 
~Shader()53 Shader::~Shader()
54 {
55 	unloadVolatile();
56 
57 	for (const auto &p : uniforms)
58 	{
59 		// Allocated with malloc().
60 		if (p.second.data != nullptr)
61 			free(p.second.data);
62 
63 		if (p.second.baseType == UNIFORM_SAMPLER)
64 		{
65 			for (int i = 0; i < p.second.count; i++)
66 			{
67 				if (p.second.textures[i] != nullptr)
68 					p.second.textures[i]->release();
69 			}
70 
71 			delete[] p.second.textures;
72 		}
73 	}
74 }
75 
mapActiveUniforms()76 void Shader::mapActiveUniforms()
77 {
78 	// Built-in uniform locations default to -1 (nonexistent.)
79 	for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
80 	{
81 		builtinUniforms[i] = -1;
82 		builtinUniformInfo[i] = nullptr;
83 	}
84 
85 	GLint activeprogram = 0;
86 	glGetIntegerv(GL_CURRENT_PROGRAM, &activeprogram);
87 
88 	gl.useProgram(program);
89 
90 	GLint numuniforms;
91 	glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numuniforms);
92 
93 	GLchar cname[256];
94 	const GLint bufsize = (GLint) (sizeof(cname) / sizeof(GLchar));
95 
96 	std::map<std::string, UniformInfo> olduniforms = uniforms;
97 	uniforms.clear();
98 
99 	for (int uindex = 0; uindex < numuniforms; uindex++)
100 	{
101 		GLsizei namelen = 0;
102 		GLenum gltype = 0;
103 		UniformInfo u = {};
104 
105 		glGetActiveUniform(program, (GLuint) uindex, bufsize, &namelen, &u.count, &gltype, cname);
106 
107 		u.name = std::string(cname, (size_t) namelen);
108 		u.location = glGetUniformLocation(program, u.name.c_str());
109 		u.baseType = getUniformBaseType(gltype);
110 		u.textureType = getUniformTextureType(gltype);
111 		u.isDepthSampler = isDepthTextureType(gltype);
112 
113 		if (u.baseType == UNIFORM_MATRIX)
114 			u.matrix = getMatrixSize(gltype);
115 		else
116 			u.components = getUniformTypeComponents(gltype);
117 
118 		// glGetActiveUniform appends "[0]" to the end of array uniform names...
119 		if (u.name.length() > 3)
120 		{
121 			size_t findpos = u.name.find("[0]");
122 			if (findpos != std::string::npos && findpos == u.name.length() - 3)
123 				u.name.erase(u.name.length() - 3);
124 		}
125 
126 		// If this is a built-in (LOVE-created) uniform, store the location.
127 		BuiltinUniform builtin = BUILTIN_MAX_ENUM;
128 		if (getConstant(u.name.c_str(), builtin))
129 			builtinUniforms[int(builtin)] = u.location;
130 
131 		if (u.location == -1)
132 			continue;
133 
134 		if (u.baseType == UNIFORM_SAMPLER && builtin != BUILTIN_TEXTURE_MAIN)
135 		{
136 			TextureUnit unit;
137 			unit.type = u.textureType;
138 			unit.active = true;
139 			unit.texture = gl.getDefaultTexture(u.textureType);
140 
141 			for (int i = 0; i < u.count; i++)
142 				textureUnits.push_back(unit);
143 		}
144 
145 		// Make sure previously set uniform data is preserved, and shader-
146 		// initialized values are retrieved.
147 		auto oldu = olduniforms.find(u.name);
148 		if (oldu != olduniforms.end())
149 		{
150 			u.data = oldu->second.data;
151 			u.dataSize = oldu->second.dataSize;
152 			u.textures = oldu->second.textures;
153 
154 			updateUniform(&u, u.count, true);
155 		}
156 		else
157 		{
158 			u.dataSize = 0;
159 
160 			switch (u.baseType)
161 			{
162 			case UNIFORM_FLOAT:
163 				u.dataSize = sizeof(float) * u.components * u.count;
164 				u.data = malloc(u.dataSize);
165 				break;
166 			case UNIFORM_INT:
167 			case UNIFORM_BOOL:
168 			case UNIFORM_SAMPLER:
169 				u.dataSize = sizeof(int) * u.components * u.count;
170 				u.data = malloc(u.dataSize);
171 				break;
172 			case UNIFORM_UINT:
173 				u.dataSize = sizeof(unsigned int) * u.components * u.count;
174 				u.data = malloc(u.dataSize);
175 				break;
176 			case UNIFORM_MATRIX:
177 				u.dataSize = sizeof(float) * (u.matrix.rows * u.matrix.columns) * u.count;
178 				u.data = malloc(u.dataSize);
179 				break;
180 			default:
181 				break;
182 			}
183 
184 			if (u.dataSize > 0)
185 			{
186 				memset(u.data, 0, u.dataSize);
187 
188 				if (u.baseType == UNIFORM_SAMPLER)
189 				{
190 					int startunit = (int) textureUnits.size() - u.count;
191 
192 					if (builtin == BUILTIN_TEXTURE_MAIN)
193 						startunit = 0;
194 
195 					for (int i = 0; i < u.count; i++)
196 						u.ints[i] = startunit + i;
197 
198 					glUniform1iv(u.location, u.count, u.ints);
199 
200 					u.textures = new Texture*[u.count];
201 					memset(u.textures, 0, sizeof(Texture *) * u.count);
202 				}
203 			}
204 
205 			size_t offset = 0;
206 
207 			// Store any shader-initialized values in our own memory.
208 			for (int i = 0; i < u.count; i++)
209 			{
210 				GLint location = u.location;
211 
212 				if (u.count > 1)
213 				{
214 					std::ostringstream ss;
215 					ss << i;
216 
217 					std::string indexname = u.name + "[" + ss.str() + "]";
218 					location = glGetUniformLocation(program, indexname.c_str());
219 				}
220 
221 				if (location == -1)
222 					continue;
223 
224 				switch (u.baseType)
225 				{
226 				case UNIFORM_FLOAT:
227 					glGetUniformfv(program, location, &u.floats[offset]);
228 					offset += u.components;
229 					break;
230 				case UNIFORM_INT:
231 				case UNIFORM_BOOL:
232 					glGetUniformiv(program, location, &u.ints[offset]);
233 					offset += u.components;
234 					break;
235 				case UNIFORM_UINT:
236 					glGetUniformuiv(program, location, &u.uints[offset]);
237 					offset += u.components;
238 					break;
239 				case UNIFORM_MATRIX:
240 					glGetUniformfv(program, location, &u.floats[offset]);
241 					offset += u.matrix.rows * u.matrix.columns;
242 					break;
243 				default:
244 					break;
245 				}
246 			}
247 		}
248 
249 		uniforms[u.name] = u;
250 
251 		if (builtin != BUILTIN_MAX_ENUM)
252 			builtinUniformInfo[(int)builtin] = &uniforms[u.name];
253 
254 		if (u.baseType == UNIFORM_SAMPLER)
255 		{
256 			// Make sure all stored textures have their Volatiles loaded before
257 			// the sendTextures call, since it calls getHandle().
258 			for (int i = 0; i < u.count; i++)
259 			{
260 				if (u.textures[i] == nullptr)
261 					continue;
262 
263 				Volatile *v = dynamic_cast<Volatile *>(u.textures[i]);
264 				if (v != nullptr)
265 					v->loadVolatile();
266 			}
267 
268 			sendTextures(&u, u.textures, u.count, true);
269 		}
270 	}
271 
272 	// Make sure uniforms that existed before but don't exist anymore are
273 	// cleaned up. This theoretically shouldn't happen, but...
274 	for (const auto &p : olduniforms)
275 	{
276 		if (uniforms.find(p.first) == uniforms.end())
277 		{
278 			free(p.second.data);
279 
280 			if (p.second.baseType != UNIFORM_SAMPLER)
281 				continue;
282 
283 			for (int i = 0; i < p.second.count; i++)
284 			{
285 				if (p.second.textures[i] != nullptr)
286 					p.second.textures[i]->release();
287 			}
288 
289 			delete[] p.second.textures;
290 		}
291 	}
292 
293 	gl.useProgram(activeprogram);
294 }
295 
loadVolatile()296 bool Shader::loadVolatile()
297 {
298 	OpenGL::TempDebugGroup debuggroup("Shader load");
299 
300     // Recreating the shader program will invalidate uniforms that rely on these.
301 	canvasWasActive = false;
302     lastViewport = Rect();
303 
304 	lastPointSize = -1.0f;
305 
306 	// Invalidate the cached matrices by setting some elements to NaN.
307 	float nan = std::numeric_limits<float>::quiet_NaN();
308 	lastProjectionMatrix.setTranslation(nan, nan);
309 	lastTransformMatrix.setTranslation(nan, nan);
310 
311 	// zero out active texture list
312 	textureUnits.clear();
313 	textureUnits.push_back(TextureUnit());
314 
315 	for (const auto &stage : stages)
316 	{
317 		if (stage.get() != nullptr)
318 			stage->loadVolatile();
319 	}
320 
321 	program = glCreateProgram();
322 
323 	if (program == 0)
324 		throw love::Exception("Cannot create shader program object.");
325 
326 	for (const auto &stage : stages)
327 	{
328 		if (stage.get() != nullptr)
329 			glAttachShader(program, (GLuint) stage->getHandle());
330 	}
331 
332 	// Bind generic vertex attribute indices to names in the shader.
333 	for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
334 	{
335 		const char *name = nullptr;
336 		if (vertex::getConstant((BuiltinVertexAttribute) i, name))
337 			glBindAttribLocation(program, i, (const GLchar *) name);
338 	}
339 
340 	glLinkProgram(program);
341 
342 	GLint status;
343 	glGetProgramiv(program, GL_LINK_STATUS, &status);
344 
345 	if (status == GL_FALSE)
346 	{
347 		std::string warnings = getProgramWarnings();
348 		glDeleteProgram(program);
349 		program = 0;
350 		throw love::Exception("Cannot link shader program object:\n%s", warnings.c_str());
351 	}
352 
353 	// Get all active uniform variables in this shader from OpenGL.
354 	mapActiveUniforms();
355 
356 	for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
357 	{
358 		const char *name = nullptr;
359 		if (vertex::getConstant(BuiltinVertexAttribute(i), name))
360 			builtinAttributes[i] = glGetAttribLocation(program, name);
361 		else
362 			builtinAttributes[i] = -1;
363 	}
364 
365 	if (current == this)
366 	{
367 		// make sure glUseProgram gets called.
368 		current = nullptr;
369 		attach();
370 		updateBuiltinUniforms();
371 	}
372 
373 	return true;
374 }
375 
unloadVolatile()376 void Shader::unloadVolatile()
377 {
378 	if (program != 0)
379 	{
380 		if (current == this)
381 			gl.useProgram(0);
382 
383 		glDeleteProgram(program);
384 		program = 0;
385 	}
386 
387 	// active texture list is probably invalid, clear it
388 	textureUnits.clear();
389 	textureUnits.push_back(TextureUnit());
390 
391 	attributes.clear();
392 
393 	// And the locations of any built-in uniform variables.
394 	for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
395 		builtinUniforms[i] = -1;
396 }
397 
getProgramWarnings() const398 std::string Shader::getProgramWarnings() const
399 {
400 	GLint strsize, nullpos;
401 	glGetProgramiv(program, GL_INFO_LOG_LENGTH, &strsize);
402 
403 	if (strsize == 0)
404 		return "";
405 
406 	char *tempstr = new char[strsize];
407 	// be extra sure that the error string will be 0-terminated
408 	memset(tempstr, '\0', strsize);
409 	glGetProgramInfoLog(program, strsize, &nullpos, tempstr);
410 	tempstr[nullpos] = '\0';
411 
412 	std::string warnings(tempstr);
413 	delete[] tempstr;
414 
415 	return warnings;
416 }
417 
getWarnings() const418 std::string Shader::getWarnings() const
419 {
420 	std::string warnings;
421 	const char *stagestr;
422 
423 	for (const auto &stage : stages)
424 	{
425 		if (stage.get() == nullptr)
426 			continue;
427 
428 		const std::string &stagewarnings = stage->getWarnings();
429 
430 		if (ShaderStage::getConstant(stage->getStageType(), stagestr))
431 			warnings += std::string(stagestr) + std::string(" shader:\n") + stagewarnings;
432 	}
433 
434 	warnings += getProgramWarnings();
435 
436 	return warnings;
437 }
438 
attach()439 void Shader::attach()
440 {
441 	if (current != this)
442 	{
443 		Graphics::flushStreamDrawsGlobal();
444 
445 		gl.useProgram(program);
446 		current = this;
447 		// retain/release happens in Graphics::setShader.
448 
449 		// Make sure all textures are bound to their respective texture units.
450 		for (int i = 0; i < (int) textureUnits.size(); ++i)
451 		{
452 			const TextureUnit &unit = textureUnits[i];
453 			if (unit.active)
454 				gl.bindTextureToUnit(unit.type, unit.texture, i, false);
455 		}
456 
457 		// send any pending uniforms to the shader program.
458 		for (const auto &p : pendingUniformUpdates)
459 			updateUniform(p.first, p.second, true);
460 
461 		pendingUniformUpdates.clear();
462 	}
463 }
464 
getUniformInfo(const std::string & name) const465 const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const
466 {
467 	const auto it = uniforms.find(name);
468 
469 	if (it == uniforms.end())
470 		return nullptr;
471 
472 	return &(it->second);
473 }
474 
getUniformInfo(BuiltinUniform builtin) const475 const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const
476 {
477 	return builtinUniformInfo[(int)builtin];
478 }
479 
updateUniform(const UniformInfo * info,int count)480 void Shader::updateUniform(const UniformInfo *info, int count)
481 {
482 	updateUniform(info, count, false);
483 }
484 
updateUniform(const UniformInfo * info,int count,bool internalupdate)485 void Shader::updateUniform(const UniformInfo *info, int count, bool internalupdate)
486 {
487 	if (current != this && !internalupdate)
488 	{
489 		pendingUniformUpdates.push_back(std::make_pair(info, count));
490 		return;
491 	}
492 
493 	if (!internalupdate)
494 		flushStreamDraws();
495 
496 	int location = info->location;
497 	UniformType type = info->baseType;
498 
499 	if (type == UNIFORM_FLOAT)
500 	{
501 		switch (info->components)
502 		{
503 		case 1:
504 			glUniform1fv(location, count, info->floats);
505 			break;
506 		case 2:
507 			glUniform2fv(location, count, info->floats);
508 			break;
509 		case 3:
510 			glUniform3fv(location, count, info->floats);
511 			break;
512 		case 4:
513 			glUniform4fv(location, count, info->floats);
514 			break;
515 		}
516 	}
517 	else if (type == UNIFORM_INT || type == UNIFORM_BOOL || type == UNIFORM_SAMPLER)
518 	{
519 		switch (info->components)
520 		{
521 		case 1:
522 			glUniform1iv(location, count, info->ints);
523 			break;
524 		case 2:
525 			glUniform2iv(location, count, info->ints);
526 			break;
527 		case 3:
528 			glUniform3iv(location, count, info->ints);
529 			break;
530 		case 4:
531 			glUniform4iv(location, count, info->ints);
532 			break;
533 		}
534 	}
535 	else if (type == UNIFORM_UINT)
536 	{
537 		switch (info->components)
538 		{
539 		case 1:
540 			glUniform1uiv(location, count, info->uints);
541 			break;
542 		case 2:
543 			glUniform2uiv(location, count, info->uints);
544 			break;
545 		case 3:
546 			glUniform3uiv(location, count, info->uints);
547 			break;
548 		case 4:
549 			glUniform4uiv(location, count, info->uints);
550 			break;
551 		}
552 	}
553 	else if (type == UNIFORM_MATRIX)
554 	{
555 		int columns = info->matrix.columns;
556 		int rows = info->matrix.rows;
557 
558 		if (columns == 2 && rows == 2)
559 			glUniformMatrix2fv(location, count, GL_FALSE, info->floats);
560 		else if (columns == 3 && rows == 3)
561 			glUniformMatrix3fv(location, count, GL_FALSE, info->floats);
562 		else if (columns == 4 && rows == 4)
563 			glUniformMatrix4fv(location, count, GL_FALSE, info->floats);
564 		else if (columns == 2 && rows == 3)
565 			glUniformMatrix2x3fv(location, count, GL_FALSE, info->floats);
566 		else if (columns == 2 && rows == 4)
567 			glUniformMatrix2x4fv(location, count, GL_FALSE, info->floats);
568 		else if (columns == 3 && rows == 2)
569 			glUniformMatrix3x2fv(location, count, GL_FALSE, info->floats);
570 		else if (columns == 3 && rows == 4)
571 			glUniformMatrix3x4fv(location, count, GL_FALSE, info->floats);
572 		else if (columns == 4 && rows == 2)
573 			glUniformMatrix4x2fv(location, count, GL_FALSE, info->floats);
574 		else if (columns == 4 && rows == 3)
575 			glUniformMatrix4x3fv(location, count, GL_FALSE, info->floats);
576 	}
577 }
578 
sendTextures(const UniformInfo * info,Texture ** textures,int count)579 void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count)
580 {
581 	Shader::sendTextures(info, textures, count, false);
582 }
583 
sendTextures(const UniformInfo * info,Texture ** textures,int count,bool internalUpdate)584 void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalUpdate)
585 {
586 	if (info->baseType != UNIFORM_SAMPLER)
587 		return;
588 
589 	bool shaderactive = current == this;
590 
591 	if (!internalUpdate && shaderactive)
592 		flushStreamDraws();
593 
594 	count = std::min(count, info->count);
595 
596 	// Bind the textures to the texture units.
597 	for (int i = 0; i < count; i++)
598 	{
599 		Texture *tex = textures[i];
600 
601 		if (tex != nullptr)
602 		{
603 			if (!tex->isReadable())
604 			{
605 				if (internalUpdate)
606 					continue;
607 				else
608 					throw love::Exception("Textures with non-readable formats cannot be sampled from in a shader.");
609 			}
610 			else if (info->isDepthSampler != tex->getDepthSampleMode().hasValue)
611 			{
612 				if (internalUpdate)
613 					continue;
614 				else if (info->isDepthSampler)
615 					throw love::Exception("Depth comparison samplers in shaders can only be used with depth textures which have depth comparison set.");
616 				else
617 					throw love::Exception("Depth textures which have depth comparison set can only be used with depth/shadow samplers in shaders.");
618 			}
619 			else if (tex->getTextureType() != info->textureType)
620 			{
621 				if (internalUpdate)
622 					continue;
623 				else
624 				{
625 					const char *textypestr = "unknown";
626 					const char *shadertextypestr = "unknown";
627 					Texture::getConstant(tex->getTextureType(), textypestr);
628 					Texture::getConstant(info->textureType, shadertextypestr);
629 					throw love::Exception("Texture's type (%s) must match the type of %s (%s).", textypestr, info->name.c_str(), shadertextypestr);
630 				}
631 			}
632 
633 			tex->retain();
634 		}
635 
636 		if (info->textures[i] != nullptr)
637 			info->textures[i]->release();
638 
639 		info->textures[i] = tex;
640 
641 		GLuint gltex = 0;
642 		if (textures[i] != nullptr)
643 			gltex = (GLuint) tex->getHandle();
644 		else
645 			gltex = gl.getDefaultTexture(info->textureType);
646 
647 		int texunit = info->ints[i];
648 
649 		if (shaderactive)
650 			gl.bindTextureToUnit(info->textureType, gltex, texunit, false);
651 
652 		// Store texture id so it can be re-bound to the texture unit later.
653 		textureUnits[texunit].texture = gltex;
654 	}
655 }
656 
flushStreamDraws() const657 void Shader::flushStreamDraws() const
658 {
659 	if (current == this)
660 		Graphics::flushStreamDrawsGlobal();
661 }
662 
hasUniform(const std::string & name) const663 bool Shader::hasUniform(const std::string &name) const
664 {
665 	return uniforms.find(name) != uniforms.end();
666 }
667 
getHandle() const668 ptrdiff_t Shader::getHandle() const
669 {
670 	return program;
671 }
672 
getVertexAttributeIndex(const std::string & name)673 int Shader::getVertexAttributeIndex(const std::string &name)
674 {
675 	auto it = attributes.find(name);
676 	if (it != attributes.end())
677 		return it->second;
678 
679 	GLint location = glGetAttribLocation(program, name.c_str());
680 
681 	attributes[name] = location;
682 	return location;
683 }
684 
setVideoTextures(Texture * ytexture,Texture * cbtexture,Texture * crtexture)685 void Shader::setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture)
686 {
687 	const BuiltinUniform builtins[3] = {
688 		BUILTIN_TEXTURE_VIDEO_Y,
689 		BUILTIN_TEXTURE_VIDEO_CB,
690 		BUILTIN_TEXTURE_VIDEO_CR,
691 	};
692 
693 	Texture *textures[3] = {ytexture, cbtexture, crtexture};
694 
695 	for (int i = 0; i < 3; i++)
696 	{
697 		const UniformInfo *info = builtinUniformInfo[builtins[i]];
698 
699 		if (info != nullptr)
700 			sendTextures(info, &textures[i], 1, true);
701 	}
702 }
703 
updateScreenParams()704 void Shader::updateScreenParams()
705 {
706 	Rect view = gl.getViewport();
707 
708 	auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
709 	bool canvasActive = gfx->isCanvasActive();
710 
711 	if ((view == lastViewport && canvasWasActive == canvasActive) || current != this)
712 		return;
713 
714 	// In the shader, we do pixcoord.y = gl_FragCoord.y * params.z + params.w.
715 	// This lets us flip pixcoord.y when needed, to be consistent (drawing with
716 	// no Canvas active makes the y-values for pixel coordinates flipped.)
717 	GLfloat params[] = {
718 		(GLfloat) view.w, (GLfloat) view.h,
719 		0.0f, 0.0f,
720 	};
721 
722 	if (canvasActive)
723 	{
724 		// No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0.
725 		params[2] = 1.0f;
726 		params[3] = 0.0f;
727 	}
728 	else
729 	{
730 		// gl_FragCoord.y is flipped when drawing to the screen, so we un-flip:
731 		// pixcoord.y = gl_FragCoord.y * -1.0 + height.
732 		params[2] = -1.0f;
733 		params[3] = (GLfloat) view.h;
734 	}
735 
736 	GLint location = builtinUniforms[BUILTIN_SCREEN_SIZE];
737 	if (location >= 0)
738 		glUniform4fv(location, 1, params);
739 
740 	canvasWasActive = canvasActive;
741 	lastViewport = view;
742 }
743 
updatePointSize(float size)744 void Shader::updatePointSize(float size)
745 {
746 	if (size == lastPointSize || current != this)
747 		return;
748 
749 	GLint location = builtinUniforms[BUILTIN_POINT_SIZE];
750 	if (location >= 0)
751 		glUniform1f(location, size);
752 
753 	lastPointSize = size;
754 }
755 
updateBuiltinUniforms()756 void Shader::updateBuiltinUniforms()
757 {
758 	if (current != this)
759 		return;
760 
761 	updateScreenParams();
762 
763 	if (GLAD_ES_VERSION_2_0)
764 		updatePointSize(gl.getPointSize());
765 
766 	auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
767 
768 	const Matrix4 &curproj = gfx->getProjection();
769 	const Matrix4 &curxform = gfx->getTransform();
770 
771 	bool tpmatrixneedsupdate = false;
772 
773 	// Only upload the matrices if they've changed.
774 	if (memcmp(curxform.getElements(), lastTransformMatrix.getElements(), sizeof(float) * 16) != 0)
775 	{
776 		GLint location = builtinUniforms[BUILTIN_MATRIX_VIEW_FROM_LOCAL];
777 		if (location >= 0)
778 			glUniformMatrix4fv(location, 1, GL_FALSE, curxform.getElements());
779 
780 		// Also upload the re-calculated normal matrix, if possible. The normal
781 		// matrix is the transpose of the inverse of the rotation portion
782 		// (top-left 3x3) of the transform matrix.
783 		location = builtinUniforms[BUILTIN_MATRIX_VIEW_NORMAL_FROM_LOCAL];
784 		if (location >= 0)
785 		{
786 			Matrix3 normalmatrix = Matrix3(curxform).transposedInverse();
787 			glUniformMatrix3fv(location, 1, GL_FALSE, normalmatrix.getElements());
788 		}
789 
790 		tpmatrixneedsupdate = true;
791 		lastTransformMatrix = curxform;
792 	}
793 
794 	if (memcmp(curproj.getElements(), lastProjectionMatrix.getElements(), sizeof(float) * 16) != 0)
795 	{
796 		GLint location = builtinUniforms[BUILTIN_MATRIX_CLIP_FROM_VIEW];
797 		if (location >= 0)
798 			glUniformMatrix4fv(location, 1, GL_FALSE, curproj.getElements());
799 
800 		tpmatrixneedsupdate = true;
801 		lastProjectionMatrix = curproj;
802 	}
803 
804 	if (tpmatrixneedsupdate)
805 	{
806 		GLint location = builtinUniforms[BUILTIN_MATRIX_CLIP_FROM_LOCAL];
807 		if (location >= 0)
808 		{
809 			Matrix4 tp_matrix(curproj, curxform);
810 			glUniformMatrix4fv(location, 1, GL_FALSE, tp_matrix.getElements());
811 		}
812 	}
813 }
814 
getGLSLVersion()815 std::string Shader::getGLSLVersion()
816 {
817 	const char *tmp = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
818 
819 	if (tmp == nullptr)
820 		return "0.0";
821 
822 	// the version string always begins with a version number of the format
823 	//   major_number.minor_number
824 	// or
825 	//   major_number.minor_number.release_number
826 	// we can keep release_number, since it does not affect the check below.
827 	std::string versionstring(tmp);
828 	size_t minorendpos = versionstring.find(' ');
829 	return versionstring.substr(0, minorendpos);
830 }
831 
isSupported()832 bool Shader::isSupported()
833 {
834 	return GLAD_ES_VERSION_2_0 || (getGLSLVersion() >= "1.2");
835 }
836 
getUniformTypeComponents(GLenum type) const837 int Shader::getUniformTypeComponents(GLenum type) const
838 {
839 	if (getUniformBaseType(type) == UNIFORM_SAMPLER)
840 		return 1;
841 
842 	switch (type)
843 	{
844 	case GL_INT:
845 	case GL_UNSIGNED_INT:
846 	case GL_FLOAT:
847 	case GL_BOOL:
848 		return 1;
849 	case GL_INT_VEC2:
850 	case GL_UNSIGNED_INT_VEC2:
851 	case GL_FLOAT_VEC2:
852 	case GL_FLOAT_MAT2:
853 	case GL_BOOL_VEC2:
854 		return 2;
855 	case GL_INT_VEC3:
856 	case GL_UNSIGNED_INT_VEC3:
857 	case GL_FLOAT_VEC3:
858 	case GL_FLOAT_MAT3:
859 	case GL_BOOL_VEC3:
860 		return 3;
861 	case GL_INT_VEC4:
862 	case GL_UNSIGNED_INT_VEC4:
863 	case GL_FLOAT_VEC4:
864 	case GL_FLOAT_MAT4:
865 	case GL_BOOL_VEC4:
866 		return 4;
867 	default:
868 		return 1;
869 	}
870 }
871 
getMatrixSize(GLenum type) const872 Shader::MatrixSize Shader::getMatrixSize(GLenum type) const
873 {
874 	MatrixSize m;
875 
876 	switch (type)
877 	{
878 	case GL_FLOAT_MAT2:
879 		m.columns = m.rows = 2;
880 		break;
881 	case GL_FLOAT_MAT3:
882 		m.columns = m.rows = 3;
883 		break;
884 	case GL_FLOAT_MAT4:
885 		m.columns = m.rows = 4;
886 		break;
887 	case GL_FLOAT_MAT2x3:
888 		m.columns = 2;
889 		m.rows = 3;
890 		break;
891 	case GL_FLOAT_MAT2x4:
892 		m.columns = 2;
893 		m.rows = 4;
894 		break;
895 	case GL_FLOAT_MAT3x2:
896 		m.columns = 3;
897 		m.rows = 2;
898 		break;
899 	case GL_FLOAT_MAT3x4:
900 		m.columns = 3;
901 		m.rows = 4;
902 		break;
903 	case GL_FLOAT_MAT4x2:
904 		m.columns = 4;
905 		m.rows = 2;
906 		break;
907 	case GL_FLOAT_MAT4x3:
908 		m.columns = 4;
909 		m.rows = 3;
910 		break;
911 	}
912 
913 	return m;
914 }
915 
getUniformBaseType(GLenum type) const916 Shader::UniformType Shader::getUniformBaseType(GLenum type) const
917 {
918 	switch (type)
919 	{
920 	case GL_INT:
921 	case GL_INT_VEC2:
922 	case GL_INT_VEC3:
923 	case GL_INT_VEC4:
924 		return UNIFORM_INT;
925 	case GL_UNSIGNED_INT:
926 	case GL_UNSIGNED_INT_VEC2:
927 	case GL_UNSIGNED_INT_VEC3:
928 	case GL_UNSIGNED_INT_VEC4:
929 		return UNIFORM_UINT;
930 	case GL_FLOAT:
931 	case GL_FLOAT_VEC2:
932 	case GL_FLOAT_VEC3:
933 	case GL_FLOAT_VEC4:
934 		return UNIFORM_FLOAT;
935 	case GL_FLOAT_MAT2:
936 	case GL_FLOAT_MAT3:
937 	case GL_FLOAT_MAT4:
938 	case GL_FLOAT_MAT2x3:
939 	case GL_FLOAT_MAT2x4:
940 	case GL_FLOAT_MAT3x2:
941 	case GL_FLOAT_MAT3x4:
942 	case GL_FLOAT_MAT4x2:
943 	case GL_FLOAT_MAT4x3:
944 		return UNIFORM_MATRIX;
945 	case GL_BOOL:
946 	case GL_BOOL_VEC2:
947 	case GL_BOOL_VEC3:
948 	case GL_BOOL_VEC4:
949 		return UNIFORM_BOOL;
950 	case GL_SAMPLER_1D:
951 	case GL_SAMPLER_1D_SHADOW:
952 	case GL_SAMPLER_1D_ARRAY:
953 	case GL_SAMPLER_1D_ARRAY_SHADOW:
954 	case GL_SAMPLER_2D:
955 	case GL_SAMPLER_2D_MULTISAMPLE:
956 	case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
957 	case GL_SAMPLER_2D_RECT:
958 	case GL_SAMPLER_2D_RECT_SHADOW:
959 	case GL_SAMPLER_2D_SHADOW:
960 	case GL_SAMPLER_2D_ARRAY:
961 	case GL_SAMPLER_2D_ARRAY_SHADOW:
962 	case GL_SAMPLER_3D:
963 	case GL_SAMPLER_CUBE:
964 	case GL_SAMPLER_CUBE_SHADOW:
965 	case GL_SAMPLER_CUBE_MAP_ARRAY:
966 	case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
967 		return UNIFORM_SAMPLER;
968 	default:
969 		return UNIFORM_UNKNOWN;
970 	}
971 }
972 
getUniformTextureType(GLenum type) const973 TextureType Shader::getUniformTextureType(GLenum type) const
974 {
975 	switch (type)
976 	{
977 	case GL_SAMPLER_1D:
978 	case GL_SAMPLER_1D_SHADOW:
979 	case GL_SAMPLER_1D_ARRAY:
980 	case GL_SAMPLER_1D_ARRAY_SHADOW:
981 		// 1D-typed textures are not supported.
982 		return TEXTURE_MAX_ENUM;
983 	case GL_SAMPLER_2D:
984 	case GL_SAMPLER_2D_SHADOW:
985 		return TEXTURE_2D;
986 	case GL_SAMPLER_2D_MULTISAMPLE:
987 	case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
988 		// Multisample textures are not supported.
989 		return TEXTURE_MAX_ENUM;
990 	case GL_SAMPLER_2D_RECT:
991 	case GL_SAMPLER_2D_RECT_SHADOW:
992 		// Rectangle textures are not supported.
993 		return TEXTURE_MAX_ENUM;
994 	case GL_SAMPLER_2D_ARRAY:
995 	case GL_SAMPLER_2D_ARRAY_SHADOW:
996 		return TEXTURE_2D_ARRAY;
997 	case GL_SAMPLER_3D:
998 		return TEXTURE_VOLUME;
999 	case GL_SAMPLER_CUBE:
1000 	case GL_SAMPLER_CUBE_SHADOW:
1001 		return TEXTURE_CUBE;
1002 	case GL_SAMPLER_CUBE_MAP_ARRAY:
1003 	case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
1004 		// Cubemap array textures are not supported.
1005 		return TEXTURE_MAX_ENUM;
1006 	default:
1007 		return TEXTURE_MAX_ENUM;
1008 	}
1009 }
1010 
isDepthTextureType(GLenum type) const1011 bool Shader::isDepthTextureType(GLenum type) const
1012 {
1013 	switch (type)
1014 	{
1015 	case GL_SAMPLER_1D_SHADOW:
1016 	case GL_SAMPLER_1D_ARRAY_SHADOW:
1017 	case GL_SAMPLER_2D_SHADOW:
1018 	case GL_SAMPLER_2D_ARRAY_SHADOW:
1019 	case GL_SAMPLER_CUBE_SHADOW:
1020 	case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
1021 		return true;
1022 	default:
1023 		return false;
1024 	}
1025 }
1026 
1027 } // opengl
1028 } // graphics
1029 } // love
1030