diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 602b9ccc4..54071ed82 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/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, diff --git a/platform/xcode/love.xcodeproj/project.pbxproj b/platform/xcode/love.xcodeproj/project.pbxproj index 7b78fdd03..326654779 100644 --- a/platform/xcode/love.xcodeproj/project.pbxproj +++ b/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]" = ( diff --git a/src/common/android.cpp b/src/common/android.cpp index 0b7724ef0..22a6ccefa 100644 --- a/src/common/android.cpp +++ b/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); diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index fe2ae7339..f0c2cdfd7 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -268,7 +268,7 @@ Shader *Graphics::newShader(const std::vector &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 &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); diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index e8d37abd8..df1990fc3 100644 --- a/src/modules/graphics/Shader.cpp +++ b/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; diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index 2c4717626..d75a6100c 100644 --- a/src/modules/graphics/Shader.h +++ b/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; }; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 08ad88b20..3c6437a62 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/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()); diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index d3ac04fd2..7d6c0faab 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/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) diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 2ae6d13f4..df7317f53 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/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: diff --git a/src/modules/graphics/opengl/Texture.cpp b/src/modules/graphics/opengl/Texture.cpp index 669753404..2d7c8a62f 100644 --- a/src/modules/graphics/opengl/Texture.cpp +++ b/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); + if (attachment == GL_NONE) + continue; - gl.clearDepth(1.0); - glClearStencil(0); - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - 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 emptydata(getPixelFormatSliceSize(format, w, h)); + for (int mip = 0; mip < clearmips; mip++) + { + int mipw = getPixelWidth(mip); + int miph = getPixelHeight(mip); + std::vector emptydata(getPixelFormatSliceSize(format, mipw, miph)); - 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); + 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(); } diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index 8cc02f9bb..c6f1c5d2f 100644 --- a/src/modules/love/love.cpp +++ b/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 diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 5bad632be..3425bd85a 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/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;