1 /**
2  * Copyright (c) 2006-2016 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 "Canvas.h"
26 
27 // C++
28 #include <algorithm>
29 #include <limits>
30 
31 namespace love
32 {
33 namespace graphics
34 {
35 namespace opengl
36 {
37 
38 namespace
39 {
40 	// temporarily attaches a shader program (for setting uniforms, etc)
41 	// reattaches the originally active program when destroyed
42 	struct TemporaryAttacher
43 	{
TemporaryAttacherlove::graphics::opengl::__anonfe70ebfb0111::TemporaryAttacher44 		TemporaryAttacher(Shader *shader)
45 		: curShader(shader)
46 		, prevShader(Shader::current)
47 		{
48 			curShader->attach(true);
49 		}
50 
~TemporaryAttacherlove::graphics::opengl::__anonfe70ebfb0111::TemporaryAttacher51 		~TemporaryAttacher()
52 		{
53 			if (prevShader != nullptr)
54 				prevShader->attach();
55 			else
56 				curShader->detach();
57 		}
58 
59 		Shader *curShader;
60 		Shader *prevShader;
61 	};
62 } // anonymous namespace
63 
64 
65 Shader *Shader::current = nullptr;
66 Shader *Shader::defaultShader = nullptr;
67 Shader *Shader::defaultVideoShader = nullptr;
68 
69 Shader::ShaderSource Shader::defaultCode[Graphics::RENDERER_MAX_ENUM][2];
70 Shader::ShaderSource Shader::defaultVideoCode[Graphics::RENDERER_MAX_ENUM][2];
71 
72 std::vector<int> Shader::textureCounters;
73 
Shader(const ShaderSource & source)74 Shader::Shader(const ShaderSource &source)
75 	: shaderSource(source)
76 	, program(0)
77 	, builtinUniforms()
78 	, builtinAttributes()
79 	, lastCanvas((Canvas *) -1)
80 	, lastViewport()
81 	, lastPointSize(0.0f)
82 	, videoTextureUnits()
83 {
84 	if (source.vertex.empty() && source.pixel.empty())
85 		throw love::Exception("Cannot create shader: no source code!");
86 
87 	// initialize global texture id counters if needed
88 	if ((int) textureCounters.size() < gl.getMaxTextureUnits() - 1)
89 		textureCounters.resize(gl.getMaxTextureUnits() - 1, 0);
90 
91 	// load shader source and create program object
92 	loadVolatile();
93 }
94 
~Shader()95 Shader::~Shader()
96 {
97 	if (current == this)
98 		detach();
99 
100 	for (const auto &retainable : boundRetainables)
101 		retainable.second->release();
102 
103 	boundRetainables.clear();
104 
105 	unloadVolatile();
106 }
107 
compileCode(ShaderStage stage,const std::string & code)108 GLuint Shader::compileCode(ShaderStage stage, const std::string &code)
109 {
110 	GLenum glstage;
111 	const char *typestr;
112 
113 	if (!stageNames.find(stage, typestr))
114 		typestr = "";
115 
116 	switch (stage)
117 	{
118 	case STAGE_VERTEX:
119 		glstage = GL_VERTEX_SHADER;
120 		break;
121 	case STAGE_PIXEL:
122 		glstage = GL_FRAGMENT_SHADER;
123 		break;
124 	default:
125 		throw love::Exception("Cannot create shader object: unknown shader type.");
126 		break;
127 	}
128 
129 	GLuint shaderid = glCreateShader(glstage);
130 
131 	if (shaderid == 0)
132 	{
133 		if (glGetError() == GL_INVALID_ENUM)
134 			throw love::Exception("Cannot create %s shader object: %s shaders not supported.", typestr, typestr);
135 		else
136 			throw love::Exception("Cannot create %s shader object.", typestr);
137 	}
138 
139 	const char *src = code.c_str();
140 	GLint srclen = (GLint) code.length();
141 	glShaderSource(shaderid, 1, (const GLchar **)&src, &srclen);
142 
143 	glCompileShader(shaderid);
144 
145 	GLint infologlen;
146 	glGetShaderiv(shaderid, GL_INFO_LOG_LENGTH, &infologlen);
147 
148 	// Get any warnings the shader compiler may have produced.
149 	if (infologlen > 0)
150 	{
151 		GLchar *infolog = new GLchar[infologlen];
152 		glGetShaderInfoLog(shaderid, infologlen, nullptr, infolog);
153 
154 		// Save any warnings for later querying.
155 		shaderWarnings[stage] = infolog;
156 
157 		delete[] infolog;
158 	}
159 
160 	GLint status;
161 	glGetShaderiv(shaderid, GL_COMPILE_STATUS, &status);
162 
163 	if (status == GL_FALSE)
164 	{
165 		glDeleteShader(shaderid);
166 		throw love::Exception("Cannot compile %s shader code:\n%s",
167 		                      typestr, shaderWarnings[stage].c_str());
168 	}
169 
170 	return shaderid;
171 }
172 
mapActiveUniforms()173 void Shader::mapActiveUniforms()
174 {
175 	// Built-in uniform locations default to -1 (nonexistant.)
176 	for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
177 		builtinUniforms[i] = -1;
178 
179 	uniforms.clear();
180 
181 	GLint activeprogram = 0;
182 	glGetIntegerv(GL_CURRENT_PROGRAM, &activeprogram);
183 
184 	gl.useProgram(program);
185 
186 	GLint numuniforms;
187 	glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numuniforms);
188 
189 	GLchar cname[256];
190 	const GLint bufsize = (GLint) (sizeof(cname) / sizeof(GLchar));
191 
192 	for (int i = 0; i < numuniforms; i++)
193 	{
194 		GLsizei namelen = 0;
195 		GLenum gltype = 0;
196 		UniformInfo u = {};
197 
198 		glGetActiveUniform(program, (GLuint) i, bufsize, &namelen, &u.count, &gltype, cname);
199 
200 		u.name = std::string(cname, (size_t) namelen);
201 		u.location = glGetUniformLocation(program, u.name.c_str());
202 		u.baseType = getUniformBaseType(gltype);
203 		u.components = getUniformTypeSize(gltype);
204 
205 		// Initialize all samplers to 0. Both GLSL and GLSL ES are supposed to
206 		// do this themselves, but some Android devices (galaxy tab 3 and 4)
207 		// don't seem to do it...
208 		if (u.baseType == UNIFORM_SAMPLER)
209 			glUniform1i(u.location, 0);
210 
211 		// glGetActiveUniform appends "[0]" to the end of array uniform names...
212 		if (u.name.length() > 3)
213 		{
214 			size_t findpos = u.name.find("[0]");
215 			if (findpos != std::string::npos && findpos == u.name.length() - 3)
216 				u.name.erase(u.name.length() - 3);
217 		}
218 
219 		// If this is a built-in (LOVE-created) uniform, store the location.
220 		BuiltinUniform builtin;
221 		if (builtinNames.find(u.name.c_str(), builtin))
222 			builtinUniforms[int(builtin)] = u.location;
223 
224 		if (u.location != -1)
225 			uniforms[u.name] = u;
226 	}
227 
228 	gl.useProgram(activeprogram);
229 }
230 
loadVolatile()231 bool Shader::loadVolatile()
232 {
233 	OpenGL::TempDebugGroup debuggroup("Shader load");
234 
235     // Recreating the shader program will invalidate uniforms that rely on these.
236     lastCanvas = (Canvas *) -1;
237     lastViewport = OpenGL::Viewport();
238 
239 	lastPointSize = -1.0f;
240 
241 	// Invalidate the cached matrices by setting some elements to NaN.
242 	float nan = std::numeric_limits<float>::quiet_NaN();
243 	lastProjectionMatrix.setTranslation(nan, nan);
244 	lastTransformMatrix.setTranslation(nan, nan);
245 
246 	for (int i = 0; i < 3; i++)
247 		videoTextureUnits[i] = 0;
248 
249 	// zero out active texture list
250 	activeTexUnits.clear();
251 	activeTexUnits.insert(activeTexUnits.begin(), gl.getMaxTextureUnits() - 1, 0);
252 
253 	std::vector<GLuint> shaderids;
254 
255 	bool gammacorrect = graphics::isGammaCorrect();
256 	const ShaderSource *defaults = &defaultCode[Graphics::RENDERER_OPENGL][gammacorrect ? 1 : 0];
257 	if (GLAD_ES_VERSION_2_0)
258 		defaults = &defaultCode[Graphics::RENDERER_OPENGLES][gammacorrect ? 1 : 0];
259 
260 	// The shader program must have both vertex and pixel shader stages.
261 	const std::string &vertexcode = shaderSource.vertex.empty() ? defaults->vertex : shaderSource.vertex;
262 	const std::string &pixelcode = shaderSource.pixel.empty() ? defaults->pixel : shaderSource.pixel;
263 
264 	try
265 	{
266 		shaderids.push_back(compileCode(STAGE_VERTEX, vertexcode));
267 		shaderids.push_back(compileCode(STAGE_PIXEL, pixelcode));
268 	}
269 	catch (love::Exception &)
270 	{
271 		for (GLuint id : shaderids)
272 			glDeleteShader(id);
273 		throw;
274 	}
275 
276 	program = glCreateProgram();
277 
278 	if (program == 0)
279 	{
280 		for (GLuint id : shaderids)
281 			glDeleteShader(id);
282 		throw love::Exception("Cannot create shader program object.");
283 	}
284 
285 	for (GLuint id : shaderids)
286 		glAttachShader(program, id);
287 
288 	// Bind generic vertex attribute indices to names in the shader.
289 	for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
290 	{
291 		const char *name = nullptr;
292 		if (attribNames.find((VertexAttribID) i, name))
293 			glBindAttribLocation(program, i, (const GLchar *) name);
294 	}
295 
296 	glLinkProgram(program);
297 
298 	// Flag shaders for auto-deletion when the program object is deleted.
299 	for (GLuint id : shaderids)
300 		glDeleteShader(id);
301 
302 	GLint status;
303 	glGetProgramiv(program, GL_LINK_STATUS, &status);
304 
305 	if (status == GL_FALSE)
306 	{
307 		std::string warnings = getProgramWarnings();
308 		glDeleteProgram(program);
309 		program = 0;
310 		throw love::Exception("Cannot link shader program object:\n%s", warnings.c_str());
311 	}
312 
313 	// Get all active uniform variables in this shader from OpenGL.
314 	mapActiveUniforms();
315 
316 	for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
317 	{
318 		const char *name = nullptr;
319 		if (attribNames.find(VertexAttribID(i), name))
320 			builtinAttributes[i] = glGetAttribLocation(program, name);
321 		else
322 			builtinAttributes[i] = -1;
323 	}
324 
325 	if (current == this)
326 	{
327 		// make sure glUseProgram gets called.
328 		current = nullptr;
329 		attach();
330 		checkSetBuiltinUniforms();
331 	}
332 
333 	return true;
334 }
335 
unloadVolatile()336 void Shader::unloadVolatile()
337 {
338 	if (current == this)
339 		gl.useProgram(0);
340 
341 	if (program != 0)
342 	{
343 		glDeleteProgram(program);
344 		program = 0;
345 	}
346 
347 	// decrement global texture id counters for texture units which had textures bound from this shader
348 	for (size_t i = 0; i < activeTexUnits.size(); ++i)
349 	{
350 		if (activeTexUnits[i] > 0)
351 			textureCounters[i] = std::max(textureCounters[i] - 1, 0);
352 	}
353 
354 	// active texture list is probably invalid, clear it
355 	activeTexUnits.clear();
356 	activeTexUnits.resize(gl.getMaxTextureUnits() - 1, 0);
357 
358 	attributes.clear();
359 
360 	// same with uniform location list
361 	uniforms.clear();
362 
363 	// And the locations of any built-in uniform variables.
364 	for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
365 		builtinUniforms[i] = -1;
366 
367 	shaderWarnings.clear();
368 }
369 
getProgramWarnings() const370 std::string Shader::getProgramWarnings() const
371 {
372 	GLint strsize, nullpos;
373 	glGetProgramiv(program, GL_INFO_LOG_LENGTH, &strsize);
374 
375 	if (strsize == 0)
376 		return "";
377 
378 	char *tempstr = new char[strsize];
379 	// be extra sure that the error string will be 0-terminated
380 	memset(tempstr, '\0', strsize);
381 	glGetProgramInfoLog(program, strsize, &nullpos, tempstr);
382 	tempstr[nullpos] = '\0';
383 
384 	std::string warnings(tempstr);
385 	delete[] tempstr;
386 
387 	return warnings;
388 }
389 
getWarnings() const390 std::string Shader::getWarnings() const
391 {
392 	std::string warnings;
393 	const char *stagestr;
394 
395 	// Get the individual shader stage warnings
396 	for (const auto &warning : shaderWarnings)
397 	{
398 		if (stageNames.find(warning.first, stagestr))
399 			warnings += std::string(stagestr) + std::string(" shader:\n") + warning.second;
400 	}
401 
402 	warnings += getProgramWarnings();
403 
404 	return warnings;
405 }
406 
attach(bool temporary)407 void Shader::attach(bool temporary)
408 {
409 	if (current != this)
410 	{
411 		gl.useProgram(program);
412 		current = this;
413 		// retain/release happens in Graphics::setShader.
414 
415 		if (!temporary)
416 		{
417 			// make sure all sent textures are properly bound to their respective texture units
418 			// note: list potentially contains texture ids of deleted/invalid textures!
419 			for (size_t i = 0; i < activeTexUnits.size(); ++i)
420 			{
421 				if (activeTexUnits[i] > 0)
422 					gl.bindTextureToUnit(activeTexUnits[i], i + 1, false);
423 			}
424 
425 			// We always want to use texture unit 0 for everyhing else.
426 			gl.setTextureUnit(0);
427 		}
428 	}
429 }
430 
detach()431 void Shader::detach()
432 {
433 	if (defaultShader)
434 	{
435 		if (current != defaultShader)
436 			defaultShader->attach();
437 
438 		return;
439 	}
440 
441 	if (current != nullptr)
442 		gl.useProgram(0);
443 
444 	current = nullptr;
445 }
446 
getUniformInfo(const std::string & name) const447 const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const
448 {
449 	const auto it = uniforms.find(name);
450 
451 	if (it == uniforms.end())
452 		return nullptr;
453 
454 	return &(it->second);
455 }
456 
sendInts(const UniformInfo * info,const int * vec,int count)457 void Shader::sendInts(const UniformInfo *info, const int *vec, int count)
458 {
459 	if (info->baseType != UNIFORM_INT && info->baseType != UNIFORM_BOOL)
460 		return;
461 
462 	TemporaryAttacher attacher(this);
463 
464 	int location = info->location;
465 
466 	switch (info->components)
467 	{
468 	case 4:
469 		glUniform4iv(location, count, vec);
470 		break;
471 	case 3:
472 		glUniform3iv(location, count, vec);
473 		break;
474 	case 2:
475 		glUniform2iv(location, count, vec);
476 		break;
477 	case 1:
478 	default:
479 		glUniform1iv(location, count, vec);
480 		break;
481 	}
482 }
483 
sendFloats(const UniformInfo * info,const float * vec,int count)484 void Shader::sendFloats(const UniformInfo *info, const float *vec, int count)
485 {
486 	if (info->baseType != UNIFORM_FLOAT && info->baseType != UNIFORM_BOOL)
487 		return;
488 
489 	TemporaryAttacher attacher(this);
490 
491 	int location = info->location;
492 
493 	switch (info->components)
494 	{
495 	case 4:
496 		glUniform4fv(location, count, vec);
497 		break;
498 	case 3:
499 		glUniform3fv(location, count, vec);
500 		break;
501 	case 2:
502 		glUniform2fv(location, count, vec);
503 		break;
504 	case 1:
505 	default:
506 		glUniform1fv(location, count, vec);
507 		break;
508 	}
509 }
510 
sendMatrices(const UniformInfo * info,const float * m,int count)511 void Shader::sendMatrices(const UniformInfo *info, const float *m, int count)
512 {
513 	if (info->baseType != UNIFORM_MATRIX)
514 		return;
515 
516 	TemporaryAttacher attacher(this);
517 
518 	int location = info->location;
519 
520 	switch (info->components)
521 	{
522 	case 4:
523 		glUniformMatrix4fv(location, count, GL_FALSE, m);
524 		break;
525 	case 3:
526 		glUniformMatrix3fv(location, count, GL_FALSE, m);
527 		break;
528 	case 2:
529 	default:
530 		glUniformMatrix2fv(location, count, GL_FALSE, m);
531 		break;
532 	}
533 }
534 
sendTexture(const UniformInfo * info,Texture * texture)535 void Shader::sendTexture(const UniformInfo *info, Texture *texture)
536 {
537 	if (info->baseType != UNIFORM_SAMPLER)
538 		return;
539 
540 	GLuint gltex = *(GLuint *) texture->getHandle();
541 
542 	TemporaryAttacher attacher(this);
543 
544 	int texunit = getTextureUnit(info->name);
545 
546 	// bind texture to assigned texture unit and send uniform to shader program
547 	gl.bindTextureToUnit(gltex, texunit, true);
548 
549 	glUniform1i(info->location, texunit);
550 
551 	// increment global shader texture id counter for this texture unit, if we haven't already
552 	if (activeTexUnits[texunit-1] == 0)
553 		++textureCounters[texunit-1];
554 
555 	// store texture id so it can be re-bound to the proper texture unit later
556 	activeTexUnits[texunit-1] = gltex;
557 
558 	retainObject(info->name, texture);
559 }
560 
retainObject(const std::string & name,Object * object)561 void Shader::retainObject(const std::string &name, Object *object)
562 {
563 	object->retain();
564 
565 	auto it = boundRetainables.find(name);
566 	if (it != boundRetainables.end())
567 		it->second->release();
568 
569 	boundRetainables[name] = object;
570 }
571 
getTextureUnit(const std::string & name)572 int Shader::getTextureUnit(const std::string &name)
573 {
574 	auto it = texUnitPool.find(name);
575 
576 	if (it != texUnitPool.end())
577 		return it->second;
578 
579 	int texunit = 1;
580 
581 	// prefer texture units which are unused by all other shaders
582 	auto freeunit_it = std::find(textureCounters.begin(), textureCounters.end(), 0);
583 
584 	if (freeunit_it != textureCounters.end())
585 	{
586 		// we don't want to use unit 0
587 		texunit = (int) std::distance(textureCounters.begin(), freeunit_it) + 1;
588 	}
589 	else
590 	{
591 		// no completely unused texture units exist, try to use next free slot in our own list
592 		auto nextunit_it = std::find(activeTexUnits.begin(), activeTexUnits.end(), 0);
593 
594 		if (nextunit_it == activeTexUnits.end())
595 			throw love::Exception("No more texture units available for shader.");
596 
597 		// we don't want to use unit 0
598 		texunit = (int) std::distance(activeTexUnits.begin(), nextunit_it) + 1;
599 	}
600 
601 	texUnitPool[name] = texunit;
602 	return texunit;
603 }
604 
getExternVariable(const std::string & name,int & components,int & count)605 Shader::UniformType Shader::getExternVariable(const std::string &name, int &components, int &count)
606 {
607 	auto it = uniforms.find(name);
608 
609 	if (it == uniforms.end())
610 	{
611 		components = 0;
612 		count = 0;
613 		return UNIFORM_UNKNOWN;
614 	}
615 
616 	components = it->second.components;
617 	count = (int) it->second.count;
618 
619 	// Legacy support. This whole function is gone in 0.11 anyway.
620 	if (it->second.baseType == UNIFORM_MATRIX)
621 		return UNIFORM_FLOAT;
622 	return it->second.baseType;
623 }
624 
getAttribLocation(const std::string & name)625 GLint Shader::getAttribLocation(const std::string &name)
626 {
627 	auto it = attributes.find(name);
628 	if (it != attributes.end())
629 		return it->second;
630 
631 	GLint location = glGetAttribLocation(program, name.c_str());
632 
633 	attributes[name] = location;
634 	return location;
635 }
636 
hasVertexAttrib(VertexAttribID attrib) const637 bool Shader::hasVertexAttrib(VertexAttribID attrib) const
638 {
639 	return builtinAttributes[int(attrib)] != -1;
640 }
641 
setVideoTextures(GLuint ytexture,GLuint cbtexture,GLuint crtexture)642 void Shader::setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtexture)
643 {
644 	TemporaryAttacher attacher(this);
645 
646 	// Set up the texture units that will be used by the shader to sample from
647 	// the textures, if they haven't been set up yet.
648 	if (videoTextureUnits[0] == 0)
649 	{
650 		const GLint locs[3] = {
651 			builtinUniforms[BUILTIN_VIDEO_Y_CHANNEL],
652 			builtinUniforms[BUILTIN_VIDEO_CB_CHANNEL],
653 			builtinUniforms[BUILTIN_VIDEO_CR_CHANNEL]
654 		};
655 
656 		const char *names[3] = {nullptr, nullptr, nullptr};
657 		builtinNames.find(BUILTIN_VIDEO_Y_CHANNEL,  names[0]);
658 		builtinNames.find(BUILTIN_VIDEO_CB_CHANNEL, names[1]);
659 		builtinNames.find(BUILTIN_VIDEO_CR_CHANNEL, names[2]);
660 
661 		for (int i = 0; i < 3; i++)
662 		{
663 			if (locs[i] >= 0 && names[i] != nullptr)
664 			{
665 				videoTextureUnits[i] = getTextureUnit(names[i]);
666 
667 				// Increment global shader texture id counter for this texture
668 				// unit, if we haven't already.
669 				if (activeTexUnits[videoTextureUnits[i] - 1] == 0)
670 					++textureCounters[videoTextureUnits[i] - 1];
671 
672 				glUniform1i(locs[i], videoTextureUnits[i]);
673 			}
674 		}
675 	}
676 
677 	const GLuint textures[3] = {ytexture, cbtexture, crtexture};
678 
679 	// Bind the textures to their respective texture units.
680 	for (int i = 0; i < 3; i++)
681 	{
682 		if (videoTextureUnits[i] != 0)
683 		{
684 			// Store texture id so it can be re-bound later.
685 			activeTexUnits[videoTextureUnits[i] - 1] = textures[i];
686 			gl.bindTextureToUnit(textures[i], videoTextureUnits[i], false);
687 		}
688 	}
689 
690 	gl.setTextureUnit(0);
691 }
692 
checkSetScreenParams()693 void Shader::checkSetScreenParams()
694 {
695 	OpenGL::Viewport view = gl.getViewport();
696 
697 	if (view == lastViewport && lastCanvas == Canvas::current)
698 		return;
699 
700 	// In the shader, we do pixcoord.y = gl_FragCoord.y * params.z + params.w.
701 	// This lets us flip pixcoord.y when needed, to be consistent (drawing with
702 	// no Canvas active makes the y-values for pixel coordinates flipped.)
703 	GLfloat params[] = {
704 		(GLfloat) view.w, (GLfloat) view.h,
705 		0.0f, 0.0f,
706 	};
707 
708 	if (Canvas::current != nullptr)
709 	{
710 		// No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0.
711 		params[2] = 1.0f;
712 		params[3] = 0.0f;
713 	}
714 	else
715 	{
716 		// gl_FragCoord.y is flipped when drawing to the screen, so we un-flip:
717 		// pixcoord.y = gl_FragCoord.y * -1.0 + height.
718 		params[2] = -1.0f;
719 		params[3] = (GLfloat) view.h;
720 	}
721 
722 	GLint location = builtinUniforms[BUILTIN_SCREEN_SIZE];
723 
724 	if (location >= 0)
725 	{
726 		TemporaryAttacher attacher(this);
727 		glUniform4fv(location, 1, params);
728 	}
729 
730 	lastCanvas = Canvas::current;
731 	lastViewport = view;
732 }
733 
checkSetPointSize(float size)734 void Shader::checkSetPointSize(float size)
735 {
736 	if (size == lastPointSize)
737 		return;
738 
739 	GLint location = builtinUniforms[BUILTIN_POINT_SIZE];
740 
741 	if (location >= 0)
742 	{
743 		TemporaryAttacher attacher(this);
744 		glUniform1f(location, size);
745 	}
746 
747 	lastPointSize = size;
748 }
749 
checkSetBuiltinUniforms()750 void Shader::checkSetBuiltinUniforms()
751 {
752 	checkSetScreenParams();
753 
754 	// We use a more efficient method for sending transformation matrices to
755 	// the GPU on desktop GL.
756 	if (GLAD_ES_VERSION_2_0)
757 	{
758 		checkSetPointSize(gl.getPointSize());
759 
760 		const Matrix4 &curxform = gl.matrices.transform.back();
761 		const Matrix4 &curproj = gl.matrices.projection.back();
762 
763 		TemporaryAttacher attacher(this);
764 
765 		bool tpmatrixneedsupdate = false;
766 
767 		// Only upload the matrices if they've changed.
768 		if (memcmp(curxform.getElements(), lastTransformMatrix.getElements(), sizeof(float) * 16) != 0)
769 		{
770 			GLint location = builtinUniforms[BUILTIN_TRANSFORM_MATRIX];
771 			if (location >= 0)
772 				glUniformMatrix4fv(location, 1, GL_FALSE, curxform.getElements());
773 
774 			// Also upload the re-calculated normal matrix, if possible. The
775 			// normal matrix is the transpose of the inverse of the rotation
776 			// portion (top-left 3x3) of the transform matrix.
777 			location = builtinUniforms[BUILTIN_NORMAL_MATRIX];
778 			if (location >= 0)
779 			{
780 				Matrix3 normalmatrix = Matrix3(curxform).transposedInverse();
781 				glUniformMatrix3fv(location, 1, GL_FALSE, normalmatrix.getElements());
782 			}
783 
784 			tpmatrixneedsupdate = true;
785 			lastTransformMatrix = curxform;
786 		}
787 
788 		if (memcmp(curproj.getElements(), lastProjectionMatrix.getElements(), sizeof(float) * 16) != 0)
789 		{
790 			GLint location = builtinUniforms[BUILTIN_PROJECTION_MATRIX];
791 			if (location >= 0)
792 				glUniformMatrix4fv(location, 1, GL_FALSE, curproj.getElements());
793 
794 			tpmatrixneedsupdate = true;
795 			lastProjectionMatrix = curproj;
796 		}
797 
798 		if (tpmatrixneedsupdate)
799 		{
800 			GLint location = builtinUniforms[BUILTIN_TRANSFORM_PROJECTION_MATRIX];
801 			if (location >= 0)
802 			{
803 				Matrix4 tp_matrix(curproj * curxform);
804 				glUniformMatrix4fv(location, 1, GL_FALSE, tp_matrix.getElements());
805 			}
806 		}
807 	}
808 }
809 
getBoundRetainables() const810 const std::map<std::string, Object *> &Shader::getBoundRetainables() const
811 {
812 	return boundRetainables;
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 
getUniformTypeSize(GLenum type) const837 int Shader::getUniformTypeSize(GLenum type) const
838 {
839 	switch (type)
840 	{
841 	case GL_INT:
842 	case GL_FLOAT:
843 	case GL_BOOL:
844 	case GL_SAMPLER_1D:
845 	case GL_SAMPLER_2D:
846 	case GL_SAMPLER_3D:
847 		return 1;
848 	case GL_INT_VEC2:
849 	case GL_FLOAT_VEC2:
850 	case GL_FLOAT_MAT2:
851 	case GL_BOOL_VEC2:
852 		return 2;
853 	case GL_INT_VEC3:
854 	case GL_FLOAT_VEC3:
855 	case GL_FLOAT_MAT3:
856 	case GL_BOOL_VEC3:
857 		return 3;
858 	case GL_INT_VEC4:
859 	case GL_FLOAT_VEC4:
860 	case GL_FLOAT_MAT4:
861 	case GL_BOOL_VEC4:
862 		return 4;
863 	default:
864 		return 1;
865 	}
866 }
867 
getUniformBaseType(GLenum type) const868 Shader::UniformType Shader::getUniformBaseType(GLenum type) const
869 {
870 	switch (type)
871 	{
872 	case GL_INT:
873 	case GL_INT_VEC2:
874 	case GL_INT_VEC3:
875 	case GL_INT_VEC4:
876 		return UNIFORM_INT;
877 	case GL_FLOAT:
878 	case GL_FLOAT_VEC2:
879 	case GL_FLOAT_VEC3:
880 	case GL_FLOAT_VEC4:
881 		return UNIFORM_FLOAT;
882 	case GL_FLOAT_MAT2:
883 	case GL_FLOAT_MAT3:
884 	case GL_FLOAT_MAT4:
885 	case GL_FLOAT_MAT2x3:
886 	case GL_FLOAT_MAT2x4:
887 	case GL_FLOAT_MAT3x2:
888 	case GL_FLOAT_MAT3x4:
889 	case GL_FLOAT_MAT4x2:
890 	case GL_FLOAT_MAT4x3:
891 		return UNIFORM_MATRIX;
892 	case GL_BOOL:
893 	case GL_BOOL_VEC2:
894 	case GL_BOOL_VEC3:
895 	case GL_BOOL_VEC4:
896 		return UNIFORM_BOOL;
897 	case GL_SAMPLER_1D:
898 	case GL_SAMPLER_1D_SHADOW:
899 	case GL_SAMPLER_1D_ARRAY:
900 	case GL_SAMPLER_1D_ARRAY_SHADOW:
901 	case GL_SAMPLER_2D:
902 	case GL_SAMPLER_2D_MULTISAMPLE:
903 	case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
904 	case GL_SAMPLER_2D_RECT:
905 	case GL_SAMPLER_2D_RECT_SHADOW:
906 	case GL_SAMPLER_2D_SHADOW:
907 	case GL_SAMPLER_2D_ARRAY:
908 	case GL_SAMPLER_2D_ARRAY_SHADOW:
909 	case GL_SAMPLER_3D:
910 	case GL_SAMPLER_CUBE:
911 	case GL_SAMPLER_CUBE_SHADOW:
912 	case GL_SAMPLER_CUBE_MAP_ARRAY:
913 	case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
914 		return UNIFORM_SAMPLER;
915 	default:
916 		return UNIFORM_UNKNOWN;
917 	}
918 }
919 
getConstant(const char * in,UniformType & out)920 bool Shader::getConstant(const char *in, UniformType &out)
921 {
922 	return uniformTypes.find(in, out);
923 }
924 
getConstant(UniformType in,const char * & out)925 bool Shader::getConstant(UniformType in, const char *&out)
926 {
927 	return uniformTypes.find(in, out);
928 }
929 
getConstant(const char * in,VertexAttribID & out)930 bool Shader::getConstant(const char *in, VertexAttribID &out)
931 {
932 	return attribNames.find(in, out);
933 }
934 
getConstant(VertexAttribID in,const char * & out)935 bool Shader::getConstant(VertexAttribID in, const char *&out)
936 {
937 	return attribNames.find(in, out);
938 }
939 
940 StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM>::Entry Shader::stageNameEntries[] =
941 {
942 	{"vertex", Shader::STAGE_VERTEX},
943 	{"pixel", Shader::STAGE_PIXEL},
944 };
945 
946 StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM> Shader::stageNames(Shader::stageNameEntries, sizeof(Shader::stageNameEntries));
947 
948 StringMap<Shader::UniformType, Shader::UNIFORM_MAX_ENUM>::Entry Shader::uniformTypeEntries[] =
949 {
950 	{"float", Shader::UNIFORM_FLOAT},
951 	{"matrix", Shader::UNIFORM_MATRIX},
952 	{"int", Shader::UNIFORM_INT},
953 	{"bool", Shader::UNIFORM_BOOL},
954 	{"image", Shader::UNIFORM_SAMPLER},
955 	{"unknown", Shader::UNIFORM_UNKNOWN},
956 };
957 
958 StringMap<Shader::UniformType, Shader::UNIFORM_MAX_ENUM> Shader::uniformTypes(Shader::uniformTypeEntries, sizeof(Shader::uniformTypeEntries));
959 
960 StringMap<VertexAttribID, ATTRIB_MAX_ENUM>::Entry Shader::attribNameEntries[] =
961 {
962 	{"VertexPosition", ATTRIB_POS},
963 	{"VertexTexCoord", ATTRIB_TEXCOORD},
964 	{"VertexColor", ATTRIB_COLOR},
965 	{"ConstantColor", ATTRIB_CONSTANTCOLOR},
966 };
967 
968 StringMap<VertexAttribID, ATTRIB_MAX_ENUM> Shader::attribNames(Shader::attribNameEntries, sizeof(Shader::attribNameEntries));
969 
970 StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::Entry Shader::builtinNameEntries[] =
971 {
972 	{"TransformMatrix", Shader::BUILTIN_TRANSFORM_MATRIX},
973 	{"ProjectionMatrix", Shader::BUILTIN_PROJECTION_MATRIX},
974 	{"TransformProjectionMatrix", Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX},
975 	{"NormalMatrix", Shader::BUILTIN_NORMAL_MATRIX},
976 	{"love_PointSize", Shader::BUILTIN_POINT_SIZE},
977 	{"love_ScreenSize", Shader::BUILTIN_SCREEN_SIZE},
978 	{"love_VideoYChannel", Shader::BUILTIN_VIDEO_Y_CHANNEL},
979 	{"love_VideoCbChannel", Shader::BUILTIN_VIDEO_CB_CHANNEL},
980 	{"love_VideoCrChannel", Shader::BUILTIN_VIDEO_CR_CHANNEL},
981 };
982 
983 StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM> Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries));
984 
985 } // opengl
986 } // graphics
987 } // love
988