Browse Source

Merge branch '12.0-development' into filesystem

Alex Szpakowski 4 years ago
parent
commit
32a7d41df8

+ 13 - 10
platform/xcode/liblove.xcodeproj/project.pbxproj

@@ -4218,7 +4218,7 @@
 		08FB7793FE84155DC02AAC07 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1000;
+				LastUpgradeCheck = 1230;
 				TargetAttributes = {
 					FA0B78DC1A958B90000E1D17 = {
 						CreatedOnToolsVersion = 6.1.1;
@@ -5063,7 +5063,7 @@
 		10D5479E63C26BB35EB5482E /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
@@ -5111,10 +5111,10 @@
 					"\"$(SRCROOT)/../../src/modules\"",
 					"\"$(SRCROOT)/../../src/libraries/enet/libenet/include\"",
 				);
-				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
 				LD_RUNPATH_SEARCH_PATHS = "@rpath";
 				LIBRARY_SEARCH_PATHS = "";
-				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				MACOSX_DEPLOYMENT_TARGET = 10.9;
 				ONLY_ACTIVE_ARCH = NO;
 				SDKROOT = macosx;
 				USE_HEADERMAP = NO;
@@ -5125,7 +5125,7 @@
 		64274E785071353E1A1D0D4B /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
@@ -5177,10 +5177,10 @@
 					"\"$(SRCROOT)/../../src/modules\"",
 					"\"$(SRCROOT)/../../src/libraries/enet/libenet/include\"",
 				);
-				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
 				LD_RUNPATH_SEARCH_PATHS = "@rpath";
 				LIBRARY_SEARCH_PATHS = "";
-				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				MACOSX_DEPLOYMENT_TARGET = 10.9;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = macosx;
 				USE_HEADERMAP = NO;
@@ -5312,7 +5312,7 @@
 		FA5326C4189719C700F7BBF4 /* Distribution */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
@@ -5360,11 +5360,11 @@
 					"\"$(SRCROOT)/../../src/modules\"",
 					"\"$(SRCROOT)/../../src/libraries/enet/libenet/include\"",
 				);
-				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
 				LD_RUNPATH_SEARCH_PATHS = "@rpath";
 				LIBRARY_SEARCH_PATHS = "";
 				LLVM_LTO = YES;
-				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				MACOSX_DEPLOYMENT_TARGET = 10.9;
 				ONLY_ACTIVE_ARCH = NO;
 				SDKROOT = macosx;
 				USE_HEADERMAP = NO;
@@ -5405,6 +5405,7 @@
 					"$(inherited)",
 					"$(PROJECT_DIR)/ios/libraries/freetype",
 				);
+				MARKETING_VERSION = 11.4;
 				OTHER_LDFLAGS = (
 					"-undefined",
 					dynamic_lookup,
@@ -5448,6 +5449,7 @@
 					"$(inherited)",
 					"$(PROJECT_DIR)/ios/libraries/freetype",
 				);
+				MARKETING_VERSION = 11.4;
 				OTHER_LDFLAGS = (
 					"-undefined",
 					dynamic_lookup,
@@ -5492,6 +5494,7 @@
 					"$(inherited)",
 					"$(PROJECT_DIR)/ios/libraries/freetype",
 				);
+				MARKETING_VERSION = 11.4;
 				OTHER_LDFLAGS = (
 					"-undefined",
 					dynamic_lookup,

+ 9 - 9
platform/xcode/love.xcodeproj/project.pbxproj

@@ -503,7 +503,7 @@
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
-				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
@@ -557,9 +557,9 @@
 					"\"$(SRCROOT)/../../src/modules\"",
 				);
 				INFOPLIST_FILE = "love-Info.plist";
-				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
 				LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks";
-				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				MACOSX_DEPLOYMENT_TARGET = 10.9;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "";
 				"OTHER_LDFLAGS[arch=x86_64]" = (
@@ -582,7 +582,7 @@
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
-				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
@@ -638,10 +638,10 @@
 					"\"$(SRCROOT)/../../src/modules\"",
 				);
 				INFOPLIST_FILE = "love-Info.plist";
-				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
 				LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks";
 				LLVM_LTO = YES;
-				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				MACOSX_DEPLOYMENT_TARGET = 10.9;
 				ONLY_ACTIVE_ARCH = NO;
 				OTHER_LDFLAGS = "";
 				"OTHER_LDFLAGS[arch=x86_64]" = (
@@ -813,7 +813,7 @@
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
-				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
@@ -869,10 +869,10 @@
 					"\"$(SRCROOT)/../../src/modules\"",
 				);
 				INFOPLIST_FILE = "love-Info.plist";
-				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
 				LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks";
 				LLVM_LTO = YES;
-				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				MACOSX_DEPLOYMENT_TARGET = 10.9;
 				ONLY_ACTIVE_ARCH = NO;
 				OTHER_LDFLAGS = "";
 				"OTHER_LDFLAGS[arch=x86_64]" = (

+ 8 - 1
src/common/android.cpp

@@ -148,7 +148,14 @@ bool openURL(const std::string &url)
 	JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
 	jclass activity = env->FindClass("org/love2d/android/GameActivity");
 
-	jmethodID openURL = env->GetStaticMethodID(activity, "openURL", "(Ljava/lang/String;)Z");
+	jmethodID openURL = env->GetStaticMethodID(activity, "openURLFromLOVE", "(Ljava/lang/String;)Z");
+
+	if (openURL == nullptr)
+	{
+		env->ExceptionClear();
+		openURL = env->GetStaticMethodID(activity, "openURL", "(Ljava/lang/String;)Z");
+	}
+
 	jstring url_jstring = (jstring) env->NewStringUTF(url.c_str());
 
 	jboolean result = env->CallStaticBooleanMethod(activity, openURL, url_jstring);

+ 2 - 2
src/modules/graphics/Graphics.cpp

@@ -268,7 +268,7 @@ Shader *Graphics::newShader(const std::vector<std::string> &stagessource)
 			if (!validstages[i])
 				continue;
 
-			if (info.isStage[i])
+			if (info.stages[i] != Shader::ENTRYPOINT_NONE)
 			{
 				isanystage = true;
 				stages[i].set(newShaderStage((ShaderStage::StageType) i, source, info), Acquire::NORETAIN);
@@ -347,7 +347,7 @@ bool Graphics::validateShader(bool gles, const std::vector<std::string> &stagess
 			if (!validstages[i])
 				continue;
 
-			if (info.isStage[i])
+			if (info.stages[i] != Shader::ENTRYPOINT_NONE)
 			{
 				isanystage = true;
 				std::string glsl = Shader::createShaderStageCode(this, stype, source, info);

+ 95 - 37
src/modules/graphics/Shader.cpp

@@ -38,6 +38,7 @@ namespace graphics
 
 namespace glsl
 {
+
 static const char global_syntax[] = R"(
 #if !defined(GL_ES) && __VERSION__ < 140
 	#define lowp
@@ -60,7 +61,11 @@ static const char global_syntax[] = R"(
 	#define DepthCubeImage samplerCubeShadow
 #endif
 #define extern uniform
-#ifdef GL_EXT_texture_array
+#if defined(GL_EXT_texture_array) && (!defined(GL_ES) || __VERSION__ > 100 || defined(GL_OES_gpu_shader5))
+// Only used when !GLSLES1 to work around Ouya driver bug. But we still want it
+// enabled for glslang validation when glsl 1-on-3 is used, so also enable it if
+// OES_gpu_shader5 exists.
+#define LOVE_EXT_TEXTURE_ARRAY_ENABLED
 #extension GL_EXT_texture_array : enable
 #endif
 #ifdef GL_OES_texture_3D
@@ -122,7 +127,7 @@ void love_initializeBuiltinUniforms() {
 
 static const char global_functions[] = R"(
 #ifdef GL_ES
-	#if __VERSION__ >= 300 || defined(GL_EXT_texture_array)
+	#if __VERSION__ >= 300 || defined(LOVE_EXT_TEXTURE_ARRAY_ENABLED)
 		precision lowp sampler2DArray;
 	#endif
 	#if __VERSION__ >= 300 || defined(GL_OES_texture_3D)
@@ -158,7 +163,7 @@ static const char global_functions[] = R"(
 	#if __VERSION__ > 100 || defined(GL_OES_texture_3D)
 		vec4 Texel(sampler3D s, vec3 c) { return love_texture3D(s, c); }
 	#endif
-	#if __VERSION__ >= 130 || defined(GL_EXT_texture_array)
+	#if __VERSION__ >= 130 || defined(LOVE_EXT_TEXTURE_ARRAY_ENABLED)
 		vec4 Texel(sampler2DArray s, vec3 c) { return love_texture2DArray(s, c); }
 	#endif
 	#ifdef PIXEL
@@ -167,7 +172,7 @@ static const char global_functions[] = R"(
 		#if __VERSION__ > 100 || defined(GL_OES_texture_3D)
 			vec4 Texel(sampler3D s, vec3 c, float b) { return love_texture3D(s, c, b); }
 		#endif
-		#if __VERSION__ >= 130 || defined(GL_EXT_texture_array)
+		#if __VERSION__ >= 130 || defined(LOVE_EXT_TEXTURE_ARRAY_ENABLED)
 			vec4 Texel(sampler2DArray s, vec3 c, float b) { return love_texture2DArray(s, c, b); }
 		#endif
 	#endif
@@ -271,6 +276,16 @@ void main() {
 }
 )";
 
+static const char vertex_main_raw[] = R"(
+void vertexmain();
+
+void main() {
+	love_initializeBuiltinUniforms();
+	setPointSize();
+	vertexmain();
+}
+)";
+
 static const char pixel_header[] = R"(
 #ifdef GL_ES
 	precision mediump float;
@@ -280,29 +295,10 @@ static const char pixel_header[] = R"(
 
 #if __VERSION__ >= 130
 	#define varying in
-	// Some drivers seem to make the pixel shader do more work when multiple
-	// pixel shader outputs are defined, even when only one is actually used.
-	// TODO: We should use reflection or something instead of this, to determine
-	// how many outputs are actually used in the shader code.
-	#ifdef LOVE_MULTI_RENDER_TARGETS
-		layout(location = 0) out vec4 love_RenderTargets[love_MaxRenderTargets];
-		#define love_PixelColor love_RenderTargets[0]
-	#else
-		layout(location = 0) out vec4 love_PixelColor;
-	#endif
-#else
-	#ifdef LOVE_MULTI_RENDER_TARGETS
-		#define love_RenderTargets gl_FragData
-	#endif
-	#define love_PixelColor gl_FragColor
 #endif
 
 // Legacy
 #define love_MaxCanvases love_MaxRenderTargets
-#define love_Canvases love_RenderTargets
-#ifdef LOVE_MULTI_RENDER_TARGETS
-#define LOVE_MULTI_CANVASES 1
-#endif
 
 // See Shader::updateScreenParams in Shader.cpp.
 #define love_PixelCoord (vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenSize.z) + love_ScreenSize.w))
@@ -331,6 +327,12 @@ vec4 VideoTexel(vec2 texcoords) {
 )";
 
 static const char pixel_main[] = R"(
+#if __VERSION__ >= 130
+	layout(location = 0) out vec4 love_PixelColor;
+#else
+	#define love_PixelColor gl_FragColor
+#endif
+
 uniform sampler2D MainTex;
 varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
 varying mediump vec4 VaryingColor;
@@ -344,6 +346,30 @@ void main() {
 )";
 
 static const char pixel_main_custom[] = R"(
+#if __VERSION__ >= 130
+	// Some drivers seem to make the pixel shader do more work when multiple
+	// pixel shader outputs are defined, even when only one is actually used.
+	// TODO: We should use reflection or something instead of this, to determine
+	// how many outputs are actually used in the shader code.
+	#ifdef LOVE_MULTI_RENDER_TARGETS
+		layout(location = 0) out vec4 love_RenderTargets[love_MaxRenderTargets];
+		#define love_PixelColor love_RenderTargets[0]
+	#else
+		layout(location = 0) out vec4 love_PixelColor;
+	#endif
+#else
+	#ifdef LOVE_MULTI_RENDER_TARGETS
+		#define love_RenderTargets gl_FragData
+	#endif
+	#define love_PixelColor gl_FragColor
+#endif
+
+// Legacy
+#define love_Canvases love_RenderTargets
+#ifdef LOVE_MULTI_RENDER_TARGETS
+#define LOVE_MULTI_CANVASES 1
+#endif
+
 varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
 varying mediump vec4 VaryingColor;
 
@@ -355,6 +381,15 @@ void main() {
 }
 )";
 
+static const char pixel_main_raw[] = R"(
+void pixelmain();
+
+void main() {
+	love_initializeBuiltinUniforms();
+	pixelmain();
+}
+)";
+
 struct StageInfo
 {
 	const char *name;
@@ -362,12 +397,13 @@ struct StageInfo
 	const char *functions;
 	const char *main;
 	const char *main_custom;
+	const char *main_raw;
 };
 
 static const StageInfo stageInfo[] =
 {
-	{ "VERTEX", vertex_header, vertex_functions, vertex_main, vertex_main },
-	{ "PIXEL", pixel_header, pixel_functions, pixel_main, pixel_main_custom },
+	{ "VERTEX", vertex_header, vertex_functions, vertex_main, vertex_main, vertex_main_raw },
+	{ "PIXEL", pixel_header, pixel_functions, pixel_main, pixel_main_custom, pixel_main_raw },
 };
 
 static_assert((sizeof(stageInfo) / sizeof(StageInfo)) == ShaderStage::STAGE_MAX_ENUM, "Stages array size must match ShaderStage enum.");
@@ -396,30 +432,38 @@ static Shader::Language getTargetLanguage(const std::string &src)
 	return lang;
 }
 
-static bool isVertexCode(const std::string &src)
+static Shader::EntryPoint getVertexEntryPoint(const std::string &src)
 {
-	std::regex r("vec4\\s+position\\s*\\(");
 	std::smatch m;
-	return std::regex_search(src, m, r);
+
+	if (std::regex_search(src, m, std::regex("void\\s+vertexmain\\s*\\(")))
+		return Shader::ENTRYPOINT_RAW;
+
+	if (std::regex_search(src, m, std::regex("vec4\\s+position\\s*\\(")))
+		return Shader::ENTRYPOINT_HIGHLEVEL;
+
+	return Shader::ENTRYPOINT_NONE;
 }
 
-static bool isPixelCode(const std::string &src, bool &custompixel, bool &mrt)
+static Shader::EntryPoint getPixelEntryPoint(const std::string &src, bool &mrt)
 {
-	custompixel = false;
 	mrt = false;
 	std::smatch m;
+
+	if (std::regex_search(src, m, std::regex("void\\s+pixelmain\\s*\\(")))
+		return Shader::ENTRYPOINT_RAW;
+
 	if (std::regex_search(src, m, std::regex("vec4\\s+effect\\s*\\(")))
-		return true;
+		return Shader::ENTRYPOINT_HIGHLEVEL;
 
 	if (std::regex_search(src, m, std::regex("void\\s+effect\\s*\\(")))
 	{
-		custompixel = true;
 		if (src.find("love_RenderTargets") != std::string::npos || src.find("love_Canvases") != std::string::npos)
 			mrt = true;
-		return true;
+		return Shader::ENTRYPOINT_CUSTOM;
 	}
 
-	return false;
+	return Shader::ENTRYPOINT_NONE;
 }
 
 } // glsl
@@ -435,8 +479,8 @@ Shader::SourceInfo Shader::getSourceInfo(const std::string &src)
 {
 	SourceInfo info = {};
 	info.language = glsl::getTargetLanguage(src);
-	info.isStage[ShaderStage::STAGE_VERTEX] = glsl::isVertexCode(src);
-	info.isStage[ShaderStage::STAGE_PIXEL] = glsl::isPixelCode(src, info.customPixelFunction, info.usesMRT);
+	info.stages[ShaderStage::STAGE_VERTEX] = glsl::getVertexEntryPoint(src);
+	info.stages[ShaderStage::STAGE_PIXEL] = glsl::getPixelEntryPoint(src, info.usesMRT);
 	return info;
 }
 
@@ -445,6 +489,12 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStage::StageType
 	if (info.language == Shader::LANGUAGE_MAX_ENUM)
 		throw love::Exception("Invalid shader language");
 
+	if (info.stages[stage] == ENTRYPOINT_NONE)
+		throw love::Exception("Cannot find entry point for shader stage.");
+
+	if (info.stages[stage] == ENTRYPOINT_RAW && info.language == LANGUAGE_GLSL1)
+		throw love::Exception("Shaders using a raw entry point (vertexmain or pixelmain) must use GLSL 3 or greater.");
+
 	const auto &features = gfx->getCapabilities().features;
 
 	if (info.language == LANGUAGE_GLSL3 && !features[Graphics::FEATURE_GLSL3])
@@ -477,7 +527,15 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStage::StageType
 	ss << glsl::global_uniforms;
 	ss << glsl::global_functions;
 	ss << stageinfo.functions;
-	ss << (info.customPixelFunction ? stageinfo.main_custom : stageinfo.main);
+
+	if (info.stages[stage] == ENTRYPOINT_HIGHLEVEL)
+		ss << stageinfo.main;
+	else if (info.stages[stage] == ENTRYPOINT_CUSTOM)
+		ss << stageinfo.main_custom;
+	else if (info.stages[stage] == ENTRYPOINT_RAW)
+		ss << stageinfo.main_raw;
+	else
+		throw love::Exception("Unknown shader entry point %d", info.stages[stage]);
 	ss << ((!gles && (lang == Shader::LANGUAGE_GLSL1 || glsl1on3)) ? "#line 0\n" : "#line 1\n");
 	ss << code;
 

+ 9 - 2
src/modules/graphics/Shader.h

@@ -90,11 +90,18 @@ public:
 		STANDARD_MAX_ENUM
 	};
 
+	enum EntryPoint
+	{
+		ENTRYPOINT_NONE,
+		ENTRYPOINT_HIGHLEVEL,
+		ENTRYPOINT_CUSTOM,
+		ENTRYPOINT_RAW,
+	};
+
 	struct SourceInfo
 	{
 		Language language;
-		bool isStage[ShaderStage::STAGE_MAX_ENUM];
-		bool customPixelFunction;
+		EntryPoint stages[ShaderStage::STAGE_MAX_ENUM];
 		bool usesMRT;
 	};
 

+ 2 - 2
src/modules/graphics/opengl/Graphics.cpp

@@ -316,8 +316,8 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
 		glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
 
 	// Set whether drawing converts input from linear -> sRGB colorspace.
-	if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB
-		|| GLAD_ES_VERSION_3_0)
+	if (!gl.bugs.brokenSRGB && (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB
+		|| GLAD_EXT_framebuffer_sRGB || GLAD_ES_VERSION_3_0))
 	{
 		if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
 			gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, isGammaCorrect());

+ 30 - 10
src/modules/graphics/opengl/OpenGL.cpp

@@ -150,6 +150,16 @@ bool OpenGL::initContext()
 		if (strstr(device, "HD Graphics 4000") || strstr(device, "HD Graphics 2500"))
 			bugs.clientWaitSyncStalls = true;
 	}
+
+	if (getVendor() == VENDOR_INTEL)
+	{
+		const char *device = (const char *) glGetString(GL_RENDERER);
+		if (strstr(device, "HD Graphics 3000") || strstr(device, "HD Graphics 2000")
+			|| !strcmp(device, "Intel(R) HD Graphics") || !strcmp(device, "Intel(R) HD Graphics Family"))
+		{
+			bugs.brokenSRGB = true;
+		}
+	}
 #endif
 
 #ifdef LOVE_WINDOWS
@@ -210,8 +220,8 @@ void OpenGL::setupContext()
 	setEnableState(ENABLE_SCISSOR_TEST, state.enableState[ENABLE_SCISSOR_TEST]);
 	setEnableState(ENABLE_FACE_CULL, state.enableState[ENABLE_FACE_CULL]);
 
-	if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB
-		|| GLAD_EXT_sRGB_write_control)
+	if (!bugs.brokenSRGB && (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB
+		|| GLAD_EXT_framebuffer_sRGB || GLAD_EXT_sRGB_write_control))
 	{
 		setEnableState(ENABLE_FRAMEBUFFER_SRGB, state.enableState[ENABLE_FRAMEBUFFER_SRGB]);
 	}
@@ -391,15 +401,23 @@ void OpenGL::initOpenGLFunctions()
 		}
 	}
 
-	if (GLAD_ES_VERSION_2_0 && GLAD_OES_texture_3D && !GLAD_ES_VERSION_3_0)
+	if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
 	{
-		// Function signatures don't match, we'll have to conditionally call it
-		//fp_glTexImage3D = fp_glTexImage3DOES;
-		fp_glTexSubImage3D = fp_glTexSubImage3DOES;
-		fp_glCopyTexSubImage3D = fp_glCopyTexSubImage3DOES;
-		fp_glCompressedTexImage3D = fp_glCompressedTexImage3DOES;
-		fp_glCompressedTexSubImage3D = fp_glCompressedTexSubImage3DOES;
-		fp_glFramebufferTexture3D = fp_glFramebufferTexture3DOES;
+		// The Nvidia Tegra 3 driver (used by Ouya) claims to support GL_EXT_texture_array but
+		// segfaults if you actually try to use it. OpenGL ES 2.0 devices should use OES_texture_3D.
+		// GL_EXT_texture_array is for desktops.
+		GLAD_EXT_texture_array = false;
+
+		if (GLAD_OES_texture_3D)
+		{
+			// Function signatures don't match, we'll have to conditionally call it
+			//fp_glTexImage3D = fp_glTexImage3DOES;
+			fp_glTexSubImage3D = fp_glTexSubImage3DOES;
+			fp_glCopyTexSubImage3D = fp_glCopyTexSubImage3DOES;
+			fp_glCompressedTexImage3D = fp_glCompressedTexImage3DOES;
+			fp_glCompressedTexSubImage3D = fp_glCompressedTexSubImage3DOES;
+			fp_glFramebufferTexture3D = fp_glFramebufferTexture3DOES;
+		}
 	}
 
 	if (!GLAD_VERSION_3_2 && !GLAD_ES_VERSION_3_2 && !GLAD_ARB_draw_elements_base_vertex)
@@ -1881,6 +1899,8 @@ bool OpenGL::isPixelFormatSupported(PixelFormat pixelformat, bool rendertarget,
 		else
 			return true;
 	case PIXELFORMAT_sRGBA8_UNORM:
+		if (gl.bugs.brokenSRGB)
+			return false;
 		if (rendertarget)
 		{
 			if (GLAD_VERSION_1_0)

+ 7 - 0
src/modules/graphics/opengl/OpenGL.h

@@ -178,6 +178,13 @@ public:
 		 **/
 		bool brokenR8PixelFormat;
 
+		/**
+		 * Intel HD Graphics drivers on Windows prior to the HD 2500/4000 have
+		 * completely broken sRGB support.
+		 * https://github.com/love2d/love/issues/1592
+		 **/
+		bool brokenSRGB;
+
 		/**
 		 * Other bugs which have workarounds that don't use conditional code at
 		 * the moment:

+ 52 - 43
src/modules/graphics/opengl/Texture.cpp

@@ -34,7 +34,7 @@ namespace graphics
 namespace opengl
 {
 
-static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat format, GLuint texture, int layers, bool clear)
+static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat format, GLuint texture, int mips, int layers, bool clear)
 {
 	// get currently bound fbo to reset to it later
 	GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL);
@@ -42,11 +42,6 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo
 	glGenFramebuffers(1, &framebuffer);
 	gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, framebuffer);
 
-	// Intel driver bug: https://github.com/love2d/love/issues/1592
-	bool current_srgb = gl.isStateEnabled(OpenGL::ENABLE_FRAMEBUFFER_SRGB);
-	if (current_srgb && isPixelFormatDepthStencil(format))
-		gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, false);
-
 	if (texture != 0)
 	{
 		if (isPixelFormatDepthStencil(format) && (GLAD_ES_VERSION_3_0 || !GLAD_ES_VERSION_2_0))
@@ -68,37 +63,40 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo
 		// Make sure all faces and layers of the texture are initialized to
 		// transparent black. This is unfortunately probably pretty slow for
 		// 2D-array and 3D textures with a lot of layers...
-		for (int layer = layers - 1; layer >= 0; layer--)
+		for (int mip = mips - 1; mip >= 0; mip--)
 		{
-			for (int face = faces - 1; face >= 0; face--)
+			for (int layer = layers - 1; layer >= 0; layer--)
 			{
-				for (GLenum attachment : fmt.framebufferAttachments)
+				for (int face = faces - 1; face >= 0; face--)
 				{
-					if (attachment == GL_NONE)
-						continue;
-
-					gl.framebufferTexture(attachment, texType, texture, 0, layer, face);
-				}
-
-				if (clear)
-				{
-					if (isPixelFormatDepthStencil(format))
+					for (GLenum attachment : fmt.framebufferAttachments)
 					{
-						bool hadDepthWrites = gl.hasDepthWrites();
-						if (!hadDepthWrites) // glDepthMask also affects glClear.
-							gl.setDepthWrites(true);
-
-						gl.clearDepth(1.0);
-						glClearStencil(0);
-						glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+						if (attachment == GL_NONE)
+							continue;
 
-						if (!hadDepthWrites)
-							gl.setDepthWrites(hadDepthWrites);
+						gl.framebufferTexture(attachment, texType, texture, mip, layer, face);
 					}
-					else
+
+					if (clear)
 					{
-						glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-						glClear(GL_COLOR_BUFFER_BIT);
+						if (isPixelFormatDepthStencil(format))
+						{
+							bool hadDepthWrites = gl.hasDepthWrites();
+							if (!hadDepthWrites) // glDepthMask also affects glClear.
+								gl.setDepthWrites(true);
+
+							gl.clearDepth(1.0);
+							glClearStencil(0);
+							glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+							if (!hadDepthWrites)
+								gl.setDepthWrites(hadDepthWrites);
+						}
+						else
+						{
+							glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+							glClear(GL_COLOR_BUFFER_BIT);
+						}
 					}
 				}
 			}
@@ -109,10 +107,6 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo
 
 	gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, current_fbo);
 
-	// Restore sRGB state if we turned it off above.
-	if (current_srgb && isPixelFormatDepthStencil(format))
-		gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, current_srgb);
-
 	return status;
 }
 
@@ -328,28 +322,43 @@ void Texture::createTexture()
 
 	bool hasdata = slices.get(0, 0) != nullptr;
 
+	// All mipmap levels need to be initialized - for color formats we can clear
+	// the base mip and use glGenerateMipmap after that's done. Depth and
+	// stencil formats don't always support glGenerateMipmap so we need to
+	// individually clear each mip level in that case. We avoid doing that for
+	// color formats because of an Intel driver bug:
+	// https://github.com/love2d/love/issues/1585
+	int clearmips = 1;
+	if (isPixelFormatDepthStencil(format))
+		clearmips = mipmapCount;
+
 	// Create a local FBO used for glReadPixels as well as MSAA blitting.
 	if (isRenderTarget())
 	{
 		bool clear = !hasdata;
 		int slices = texType == TEXTURE_VOLUME ? depth : layers;
-		framebufferStatus = createFBO(fbo, texType, format, texture, slices, clear);
+		framebufferStatus = createFBO(fbo, texType, format, texture, clearmips, slices, clear);
 	}
 	else if (!hasdata)
 	{
 		// Initialize all slices to transparent black.
-		std::vector<uint8> emptydata(getPixelFormatSliceSize(format, w, h));
-
-		Rect r = {0, 0, w, h};
-		int slices = texType == TEXTURE_VOLUME ? depth : layers;
-		slices = texType == TEXTURE_CUBE ? 6 : slices;
-		for (int i = 0; i < slices; i++)
-			uploadByteData(format, emptydata.data(), emptydata.size(), 0, i, r);
+		for (int mip = 0; mip < clearmips; mip++)
+		{
+			int mipw = getPixelWidth(mip);
+			int miph = getPixelHeight(mip);
+			std::vector<uint8> emptydata(getPixelFormatSliceSize(format, mipw, miph));
+
+			Rect r = {0, 0, mipw, miph};
+			int slices = texType == TEXTURE_VOLUME ? getDepth(mip) : layers;
+			slices = texType == TEXTURE_CUBE ? 6 : slices;
+			for (int i = 0; i < slices; i++)
+				uploadByteData(format, emptydata.data(), emptydata.size(), mip, i, r);
+		}
 	}
 
 	// Non-readable textures can't have mipmaps (enforced in the base class),
 	// so generateMipmaps here is fine - when they aren't already initialized.
-	if (getMipmapCount() > 1 && slices.getMipmapCount() <= 1)
+	if (clearmips < mipmapCount && slices.getMipmapCount() <= 1 && getMipmapsMode() != MIPMAPS_NONE)
 		generateMipmaps();
 }
 

+ 24 - 0
src/modules/love/love.cpp

@@ -371,6 +371,23 @@ static int w_deprecation__gc(lua_State *)
 	return 0;
 }
 
+static void luax_addcompatibilityalias(lua_State *L, const char *module, const char *name, const char *alias)
+{
+	lua_getglobal(L, module);
+	if (lua_istable(L, -1))
+	{
+		lua_getfield(L, -1, alias);
+		bool hasalias = !lua_isnoneornil(L, -1);
+		lua_pop(L, 1);
+		if (!hasalias)
+		{
+			lua_getfield(L, -1, name);
+			lua_setfield(L, -2, alias);
+		}
+	}
+	lua_pop(L, 1);
+}
+
 int luaopen_love(lua_State *L)
 {
 	love::luax_insistpinnedthread(L);
@@ -480,6 +497,13 @@ int luaopen_love(lua_State *L)
 	love::luax_require(L, "love.data");
 	lua_pop(L, 1);
 
+#if LUA_VERSION_NUM <= 501
+	// These are deprecated in Lua 5.1. LuaJIT 2.1 removes them, but code
+	// written assuming LuaJIT 2.0 or Lua 5.1 is used might still rely on them.
+	luax_addcompatibilityalias(L, "math", "fmod", "mod");
+	luax_addcompatibilityalias(L, "string", "gmatch", "gfind");
+#endif
+
 #ifdef LOVE_ENABLE_LUASOCKET
 	love::luasocket::__open(L);
 #endif

+ 15 - 4
src/modules/window/sdl/Window.cpp

@@ -443,15 +443,23 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
 		height = mode.h;
 	}
 
-	// On Android we always must have fullscreen type FULLSCREEN_TYPE_DESKTOP
+	// On Android, disable fullscreen first on window creation so it's
+	// possible to change the orientation by specifying portait width and
+	// height, otherwise SDL will pick the current orientation dimensions when
+	// fullscreen flag is set. Don't worry, we'll set it back later when user
+	// also requested fullscreen after the window is created.
+	// See https://github.com/love2d/love-android/issues/196
 #ifdef LOVE_ANDROID
+	bool fullscreen = f.fullscreen;
+
+	f.fullscreen = false;
 	f.fstype = FULLSCREEN_DESKTOP;
 #endif
 
 	int x = f.x;
 	int y = f.y;
 
-	if (f.useposition && !f.fullscreen)
+	if (f.useposition)
 	{
 		// The position needs to be in the global coordinate space.
 		SDL_Rect displaybounds = {};
@@ -544,7 +552,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
 	// Enforce minimum window dimensions.
 	SDL_SetWindowMinimumSize(window, f.minwidth, f.minheight);
 
-	if (this->settings.display != f.display || ((f.useposition || f.centered) && !f.fullscreen))
+	if (this->settings.display != f.display || f.useposition || f.centered)
 		SDL_SetWindowPosition(window, x, y);
 
 	SDL_RaiseWindow(window);
@@ -569,8 +577,11 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
 		}
 	}
 
+	// Set fullscreen when user requested it before.
+	// See above for explanation.
 #ifdef LOVE_ANDROID
-	love::android::setImmersive(f.fullscreen);
+	setFullscreen(fullscreen);
+	love::android::setImmersive(fullscreen);
 #endif
 
 	return true;