diff --git a/core/os/os.cpp b/core/os/os.cpp index 49fb5c257e9b5..f5cd42f7545b8 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -675,6 +675,10 @@ bool OS::has_feature(const String &p_feature) { } #endif + if (p_feature == "zero_delay_physics") { + return true; + } + if (_check_internal_feature_support(p_feature)) { return true; } diff --git a/drivers/gl_context/SCsub b/drivers/gl_context/SCsub index 3084ddd9591d9..8058e6c1d6445 100644 --- a/drivers/gl_context/SCsub +++ b/drivers/gl_context/SCsub @@ -4,7 +4,7 @@ Import("env") thirdparty_obj = [] -if env["platform"] in ["haiku", "osx", "windows", "x11"]: +if env["platform"] in ["haiku", "osx", "windows", "x11", "egl"]: # Thirdparty source files thirdparty_dir = "#thirdparty/glad/" thirdparty_sources = [ diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index a8f2f3bf0b80b..0bb7127361ede 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -411,6 +411,9 @@ void RasterizerGLES3::end_frame(bool p_swap_buffers) { } if (p_swap_buffers) { +#ifdef EGL_ENABLED + glFinish(); +#endif OS::get_singleton()->swap_buffers(); } else { glFinish(); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index f054ea42e496e..7278ecbc595bf 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -3513,7 +3513,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p //transfer to effect buffer if using buffers, also resolve MSAA glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); - glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); @@ -3866,6 +3866,11 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); } + int depth_texture_id; + glActiveTexture(GL_TEXTURE1); + glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depth_texture_id); + glBindTexture(GL_TEXTURE_2D, depth_texture_id); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, composite_from); if (env) { @@ -3966,6 +3971,10 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p _copy_screen(true, true); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + //turn off everything used state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FXAA, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_DEBANDING, false); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index b8050fd3ca936..8b466e378535b 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -2281,6 +2281,13 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { return; } + // TODO: alpha channel attempt: + /* + if (p_shader->spatial.unshaded) { + p_shader->spatial.uses_alpha = false; + } + */ + p_shader->shader->set_custom_shader_code(p_shader->custom_code_id, gen_code.vertex, gen_code.vertex_global, gen_code.fragment, gen_code.light, gen_code.fragment_global, gen_code.uniforms, gen_code.texture_uniforms, gen_code.defines); p_shader->ubo_size = gen_code.uniform_total_size; diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index 05260093b937c..a64c304e78ff7 100644 --- a/drivers/gles3/shaders/tonemap.glsl +++ b/drivers/gles3/shaders/tonemap.glsl @@ -28,6 +28,7 @@ precision mediump float; in vec2 uv_interp; uniform highp sampler2D source; //texunit:0 +uniform highp sampler2D sdepth; //texunit:1 uniform float exposure; uniform float white; @@ -414,7 +415,6 @@ vec3 apply_cas(vec3 color, float exposure, vec2 uv_interp, float sharpen_intensi void main() { vec3 color = textureLod(source, uv_interp, 0.0f).rgb; - // Exposure float full_exposure = exposure; @@ -475,5 +475,11 @@ void main() { color = apply_color_correction(color, color_correction); #endif - frag_color = vec4(color, 1.0f); + highp float depth = textureLod(sdepth, uv_interp, 0.0f).r; + const float d_min = 0.01; // camera near + const float d_max = 1000; // camera far + depth = d_min / ((1.0 - depth) + (d_min / d_max)); + depth = clamp(1.0 / (depth + 0.5), 0.0, 1.0); + + frag_color = vec4(color, depth); } diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 1d290baddf443..f26c56134088c 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -103,6 +103,7 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { int err = stat(path.utf8().get_data(), &st); if (!err) { switch (st.st_mode & S_IFMT) { + case S_IFIFO: case S_IFLNK: case S_IFREG: break; @@ -291,6 +292,7 @@ bool FileAccessUnix::file_exists(const String &p_path) { // See if this is a regular file switch (st.st_mode & S_IFMT) { + case S_IFIFO: case S_IFLNK: case S_IFREG: return true; diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index eefd5f82a2baa..c8d44cbd09ca4 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -1549,6 +1549,12 @@ void BulletPhysicsServer::step(float p_deltaTime) { } void BulletPhysicsServer::flush_queries() { + if (!active) + return; + + for (int i = 0; i < active_spaces_count; ++i) { + active_spaces[i]->flush_queries(); + } } void BulletPhysicsServer::finish() { diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 45557aad3118e..520b65bb41e8e 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -573,10 +573,6 @@ void SpaceBullet::remove_all_collision_objects() { } } -void onBulletPreTickCallback(btDynamicsWorld *p_dynamicsWorld, btScalar timeStep) { - static_cast(p_dynamicsWorld->getWorldUserInfo())->flush_queries(); -} - void onBulletTickCallback(btDynamicsWorld *p_dynamicsWorld, btScalar timeStep) { const btCollisionObjectArray &colObjArray = p_dynamicsWorld->getCollisionObjectArray(); @@ -644,7 +640,6 @@ void SpaceBullet::create_empty_world(bool p_create_soft_world) { dynamicsWorld->setWorldUserInfo(this); - dynamicsWorld->setInternalTickCallback(onBulletPreTickCallback, this, true); dynamicsWorld->setInternalTickCallback(onBulletTickCallback, this, false); dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(ghostPairCallback); // Setup ghost check dynamicsWorld->getPairCache()->setOverlapFilterCallback(godotFilterCallback); diff --git a/modules/denoise/config.py b/modules/denoise/config.py index f7278b3f78adb..3cb89745ace51 100644 --- a/modules/denoise/config.py +++ b/modules/denoise/config.py @@ -5,7 +5,7 @@ def can_build(env, platform): # as doing lightmap generation and denoising on Android or HTML5 # would be a bit far-fetched. # Note: oneDNN doesn't support ARM64, OIDN needs updating to the latest version - supported_platform = platform in ["x11", "osx", "windows", "server"] + supported_platform = platform in ["x11", "egl", "osx", "windows", "server"] supported_bits = env["bits"] == "64" supported_arch = env["arch"] != "arm64" and not env["arch"].startswith("rv") @@ -14,7 +14,7 @@ def can_build(env, platform): # bits-handling code. from platform import machine - if platform == "x11" and machine() != "x86_64": + if platform in ["x11", "egl"] and machine() != "x86_64": supported_arch = False return env["tools"] and supported_platform and supported_bits and supported_arch diff --git a/modules/gdnative/nativescript/SCsub b/modules/gdnative/nativescript/SCsub index b1ddb2489c6ee..9c36f99adfd01 100644 --- a/modules/gdnative/nativescript/SCsub +++ b/modules/gdnative/nativescript/SCsub @@ -5,5 +5,5 @@ Import("env_gdnative") env_gdnative.add_source_files(env.modules_sources, "*.cpp") -if "platform" in env and env["platform"] in ["x11", "iphone"]: +if "platform" in env and env["platform"] in ["x11", "egl", "iphone"]: env.Append(LINKFLAGS=["-rdynamic"]) diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index de29e7559900b..958505d3af56c 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -59,11 +59,11 @@ def copy_file(src_dir, dst_dir, src_name, dst_name=""): def is_desktop(platform): - return platform in ["windows", "osx", "x11", "server", "uwp", "haiku"] + return platform in ["windows", "osx", "x11", "egl", "server", "uwp", "haiku"] def is_unix_like(platform): - return platform in ["osx", "x11", "server", "android", "haiku", "iphone"] + return platform in ["osx", "x11", "egl", "server", "android", "haiku", "iphone"] def module_supports_tools_on(platform): diff --git a/modules/mono/config.py b/modules/mono/config.py index 5fb83590c4d24..84e77caa8023b 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -1,4 +1,4 @@ -supported_platforms = ["windows", "osx", "x11", "server", "android", "haiku", "javascript", "iphone"] +supported_platforms = ["windows", "osx", "x11", "egl", "server", "android", "haiku", "javascript", "iphone"] def can_build(env, platform): diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs index 86342c9bdf701..8805b3faaf1b5 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs @@ -36,6 +36,7 @@ public static class Platforms public const string Windows = "windows"; public const string OSX = "osx"; public const string X11 = "x11"; + public const string EGL = "egl"; public const string Server = "server"; public const string UWP = "uwp"; public const string Haiku = "haiku"; diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub index 8a4a6fb5f347e..469b67b62624d 100644 --- a/modules/webm/libvpx/SCsub +++ b/modules/webm/libvpx/SCsub @@ -227,7 +227,7 @@ if env["platform"] == "uwp": elif env["platform"] != "windows": # Disable for Windows, yasm SIMD optimizations trigger crash (GH-50862). import platform - is_x11_or_server_arm = (env["platform"] == "x11" or env["platform"] == "server") and ( + is_x11_or_server_arm = (env["platform"] in ["x11", "egl", "server"]) and ( platform.machine().startswith("arm") or platform.machine().startswith("aarch") ) is_macos_x86 = env["platform"] == "osx" and ("arch" in env and (env["arch"] != "arm64")) @@ -239,9 +239,7 @@ elif env["platform"] != "windows": # Disable for Windows, yasm SIMD optimizatio not is_x11_or_server_arm and (cpu_bits == "32" or cpu_bits == "64") and ( - env["platform"] == "windows" - or env["platform"] == "x11" - or env["platform"] == "haiku" + env["platform"] in ["windows", "x11", "egl", "haiku"] or is_macos_x86 or is_android_x86 or is_ios_x86 @@ -309,8 +307,7 @@ if webm_cpu_arm: elif ( env["platform"] == "android" and env["android_arch"] == "armv7" - or env["platform"] == "x11" - or env["platform"] == "server" + or env["platform"] in ["x11", "egl", "server"] ): env_libvpx["ASFLAGS"] = "-mfpu=neon" elif env["platform"] == "uwp": diff --git a/platform/egl/SCsub b/platform/egl/SCsub new file mode 100644 index 0000000000000..8a0e093656b05 --- /dev/null +++ b/platform/egl/SCsub @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +Import("env") + +from platform_methods import run_in_subprocess +import platform_egl_builders + +common_egl = [ + "context_gl_egl.cpp", + "crash_handler_egl.cpp", + "os_egl.cpp", +] + +prog = env.add_program("#bin/godot", ["godot_egl.cpp"] + common_egl) + +if env["debug_symbols"] and env["separate_debug_symbols"]: + env.AddPostAction(prog, run_in_subprocess(platform_egl_builders.make_debug_egl)) diff --git a/platform/egl/context_gl_egl.cpp b/platform/egl/context_gl_egl.cpp new file mode 100644 index 0000000000000..cccce1ab3b980 --- /dev/null +++ b/platform/egl/context_gl_egl.cpp @@ -0,0 +1,196 @@ +/*************************************************************************/ +/* context_gl_egl.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "context_gl_egl.h" + +#ifdef EGL_ENABLED + +EGLDisplay ContextGL_EGL::get_display() { + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress("eglGetPlatformDisplayEXT"); + PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC) eglGetProcAddress("eglQueryDevicesEXT"); + PFNEGLQUERYDEVICEATTRIBEXTPROC eglQueryDeviceAttribEXT = (PFNEGLQUERYDEVICEATTRIBEXTPROC) eglGetProcAddress("eglQueryDeviceAttribEXT"); + + char *env_cuda_id = std::getenv("EGL_CUDA_ID"); + int dev_cuda_id = -1; + if (env_cuda_id) { + dev_cuda_id = std::atoi(env_cuda_id); + } + + EGLDeviceEXT egl_devices[16] = {}; + EGLint num_devices = 0; + eglQueryDevicesEXT(16, &egl_devices[0], &num_devices); + + int egl_selected = -1; + int egl_fallback = -1; + int last_cuda_id = -1; + + for (int i=0; i= 0) { + return eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, egl_devices[egl_selected], NULL); + } + if (egl_fallback >= 0) { + return eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, egl_devices[egl_fallback], NULL); + } + + return eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, EGL_DEFAULT_DISPLAY, NULL); +} + +void ContextGL_EGL::release_current() { + eglMakeCurrent(eglDpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +} + +void ContextGL_EGL::make_current() { + eglMakeCurrent(eglDpy, eglSurf, eglSurf, eglCtx); +} + +void ContextGL_EGL::swap_buffers() { + eglSwapBuffers(eglDpy, eglSurf); +} + +void ContextGL_EGL::set_buffer_size(const int width, const int height) { + eglMakeCurrent(eglDpy, EGL_NO_SURFACE, EGL_NO_SURFACE, eglCtx); + eglDestroySurface(eglDpy, eglSurf); + + static const EGLint pbufferAttribs[] = { + EGL_WIDTH, width, + EGL_HEIGHT, height, + EGL_NONE, + }; + eglSurf = eglCreatePbufferSurface(eglDpy, eglCfg, pbufferAttribs); + eglMakeCurrent(eglDpy, eglSurf, eglSurf, eglCtx); +} + +Error ContextGL_EGL::initialize(const int width, const int height) { + EGLint numConfigs; + + static const EGLint visual_attribs_layers[] = { + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 24, + EGL_NONE + }; + + static const EGLint visual_attribs_simple[] = { + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_DEPTH_SIZE, 24, + EGL_NONE + }; + + static const EGLint pbufferAttribs[] = { + EGL_WIDTH, width, + EGL_HEIGHT, height, + EGL_NONE, + }; + + static const EGLint contextAttribs[] = { + EGL_CONTEXT_MAJOR_VERSION, (context_type == ContextType::GLES_3_0_COMPATIBLE) ? 3 : 2, + EGL_CONTEXT_MINOR_VERSION, (context_type == ContextType::GLES_3_0_COMPATIBLE) ? 3 : 0, + EGL_NONE, + }; + + eglDpy = get_display(); + eglInitialize(eglDpy, &egl_major, &egl_minor); + + if (OS::get_singleton()->is_layered_allowed()) { + eglChooseConfig(eglDpy, visual_attribs_layers, &eglCfg, 1, &numConfigs); + } else { + eglChooseConfig(eglDpy, visual_attribs_simple, &eglCfg, 1, &numConfigs); + } + + eglSurf = eglCreatePbufferSurface(eglDpy, eglCfg, pbufferAttribs); + eglBindAPI(EGL_OPENGL_API); + + eglCtx = eglCreateContext(eglDpy, eglCfg, EGL_NO_CONTEXT, contextAttribs); + + eglMakeCurrent(eglDpy, eglSurf, eglSurf, eglCtx); + + set_use_vsync(false); + return OK; +} + +int ContextGL_EGL::get_window_width() { + EGLint size = 0; + eglQuerySurface(eglDpy, eglSurf, EGL_WIDTH, &size); + return size; +} + +int ContextGL_EGL::get_window_height() { + EGLint size = 0; + eglQuerySurface(eglDpy, eglSurf, EGL_HEIGHT, &size); + return size; +} + +void *ContextGL_EGL::get_glx_context() { + return eglCtx; +} + +void ContextGL_EGL::set_use_vsync(bool p_use) { + eglSwapInterval(eglDpy, p_use); + use_vsync = p_use; +} +bool ContextGL_EGL::is_using_vsync() const { + return use_vsync; +} + +ContextGL_EGL::ContextGL_EGL(const OS::VideoMode &p_default_video_mode, ContextType p_context_type) { + context_type = p_context_type; + double_buffer = false; + direct_render = false; + egl_major = 0; + egl_minor = 0; +} + +ContextGL_EGL::~ContextGL_EGL() { + release_current(); + eglTerminate(eglDpy); +} + +#endif diff --git a/platform/egl/context_gl_egl.h b/platform/egl/context_gl_egl.h new file mode 100644 index 0000000000000..ccc0f662275d0 --- /dev/null +++ b/platform/egl/context_gl_egl.h @@ -0,0 +1,84 @@ +/*************************************************************************/ +/* context_gl_egl.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CONTEXT_GL_EGL_H +#define CONTEXT_GL_EGL_H + +#ifdef EGL_ENABLED + +#include "core/os/os.h" + +#include +#include + +class ContextGL_EGL { + +public: + enum ContextType { + OLDSTYLE, + GLES_2_0_COMPATIBLE, + GLES_3_0_COMPATIBLE + }; + +private: + OS::VideoMode default_video_mode; + EGLDisplay eglDpy; + EGLConfig eglCfg; + EGLSurface eglSurf; + EGLContext eglCtx; + bool double_buffer; + bool direct_render; + EGLint egl_major; + EGLint egl_minor; + bool use_vsync; + ContextType context_type; + EGLDisplay get_display(); + +public: + void release_current(); + void make_current(); + void swap_buffers(); + void set_buffer_size(const int width, const int height); + int get_window_width(); + int get_window_height(); + void *get_glx_context(); + + Error initialize(const int width, const int height); + + void set_use_vsync(bool p_use); + bool is_using_vsync() const; + + ContextGL_EGL(const OS::VideoMode &p_default_video_mode, ContextType p_context_type); + ~ContextGL_EGL(); +}; + +#endif + +#endif diff --git a/platform/egl/crash_handler_egl.cpp b/platform/egl/crash_handler_egl.cpp new file mode 100644 index 0000000000000..1114aaf2deae3 --- /dev/null +++ b/platform/egl/crash_handler_egl.cpp @@ -0,0 +1,149 @@ +/*************************************************************************/ +/* crash_handler_egl.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "crash_handler_egl.h" + +#include "core/os/os.h" +#include "core/project_settings.h" +#include "main/main.h" + +#ifdef DEBUG_ENABLED +#define CRASH_HANDLER_ENABLED 1 +#endif + +#ifdef CRASH_HANDLER_ENABLED +#include +#include +#include +#include +#include + +static void handle_crash(int sig) { + if (OS::get_singleton() == NULL) { + abort(); + } + + void *bt_buffer[256]; + size_t size = backtrace(bt_buffer, 256); + String _execpath = OS::get_singleton()->get_executable_path(); + + String msg; + const ProjectSettings *proj_settings = ProjectSettings::get_singleton(); + if (proj_settings) { + msg = proj_settings->get("debug/settings/crash_handler/message"); + } + + // Dump the backtrace to stderr with a message to the user + fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig); + + if (OS::get_singleton()->get_main_loop()) + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH); + + fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str()); + char **strings = backtrace_symbols(bt_buffer, size); + if (strings) { + for (size_t i = 1; i < size; i++) { + char fname[1024]; + Dl_info info; + + snprintf(fname, 1024, "%s", strings[i]); + + // Try to demangle the function name to provide a more readable one + if (dladdr(bt_buffer[i], &info) && info.dli_sname) { + if (info.dli_sname[0] == '_') { + int status; + char *demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status); + + if (status == 0 && demangled) { + snprintf(fname, 1024, "%s", demangled); + } + + if (demangled) + free(demangled); + } + } + + List args; + + char str[1024]; + snprintf(str, 1024, "%p", bt_buffer[i]); + args.push_back(str); + args.push_back("-e"); + args.push_back(_execpath); + + String output = ""; + + // Try to get the file/line number using addr2line + int ret; + Error err = OS::get_singleton()->execute(String("addr2line"), args, true, NULL, &output, &ret); + if (err == OK) { + output.erase(output.length() - 1, 1); + } + + fprintf(stderr, "[%ld] %s (%ls)\n", (long int)i, fname, output.c_str()); + } + + free(strings); + } + fprintf(stderr, "-- END OF BACKTRACE --\n"); + + // Abort to pass the error to the OS + abort(); +} +#endif + +CrashHandler::CrashHandler() { + disabled = false; +} + +CrashHandler::~CrashHandler() { + disable(); +} + +void CrashHandler::disable() { + if (disabled) + return; + +#ifdef CRASH_HANDLER_ENABLED + signal(SIGSEGV, NULL); + signal(SIGFPE, NULL); + signal(SIGILL, NULL); +#endif + + disabled = true; +} + +void CrashHandler::initialize() { +#ifdef CRASH_HANDLER_ENABLED + signal(SIGSEGV, handle_crash); + signal(SIGFPE, handle_crash); + signal(SIGILL, handle_crash); +#endif +} diff --git a/platform/egl/crash_handler_egl.h b/platform/egl/crash_handler_egl.h new file mode 100644 index 0000000000000..5804be117df23 --- /dev/null +++ b/platform/egl/crash_handler_egl.h @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* crash_handler_egl.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CRASH_HANDLER_EGL_H +#define CRASH_HANDLER_EGL_H + +class CrashHandler { + + bool disabled; + +public: + void initialize(); + + void disable(); + bool is_disabled() const { return disabled; }; + + CrashHandler(); + ~CrashHandler(); +}; + +#endif // CRASH_HANDLER_EGL_H diff --git a/platform/egl/detect.py b/platform/egl/detect.py new file mode 100644 index 0000000000000..afa199b5c4179 --- /dev/null +++ b/platform/egl/detect.py @@ -0,0 +1,321 @@ +import os +import platform +import sys +from methods import get_compiler_version, using_gcc, using_clang + + +def is_active(): + return True + + +def get_name(): + return "EGL" + + +def can_build(): + if os.name != "posix" or sys.platform == "darwin": + return False + + pkg_error = os.system("pkg-config --version > /dev/null") + if pkg_error: + return False + + return True + + +def get_opts(): + from SCons.Variables import BoolVariable, EnumVariable + + return [ + BoolVariable("use_llvm", "Use the LLVM compiler", False), + BoolVariable("use_lld", "Use the LLD linker", False), + BoolVariable("use_thinlto", "Use ThinLTO", False), + BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True), + BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False), + BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN))", False), + BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN))", False), + BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN))", False), + BoolVariable("use_msan", "Use LLVM/GCC compiler memory sanitizer (MSAN))", False), + BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True), + BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False), + BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", False), + ] + + +def get_flags(): + return [] + + +def configure(env): + ## Build type + + if env["target"] == "release": + if env["optimize"] == "speed": # optimize for speed (default) + env.Prepend(CCFLAGS=["-O3"]) + elif env["optimize"] == "size": # optimize for size + env.Prepend(CCFLAGS=["-Os"]) + + if env["debug_symbols"]: + env.Prepend(CCFLAGS=["-g2"]) + + elif env["target"] == "release_debug": + if env["optimize"] == "speed": # optimize for speed (default) + env.Prepend(CCFLAGS=["-O2"]) + elif env["optimize"] == "size": # optimize for size + env.Prepend(CCFLAGS=["-Os"]) + + env.Prepend(CPPDEFINES=["DEBUG_ENABLED"]) + + if env["debug_symbols"]: + env.Prepend(CCFLAGS=["-g2"]) + + elif env["target"] == "debug": + env.Prepend(CCFLAGS=["-ggdb"]) + env.Prepend(CCFLAGS=["-g3"]) + env.Prepend(CPPDEFINES=["DEBUG_ENABLED"]) + env.Append(LINKFLAGS=["-rdynamic"]) + + ## Architecture + + is64 = sys.maxsize > 2 ** 32 + if env["bits"] == "default": + env["bits"] = "64" if is64 else "32" + + ## Compiler configuration + + if "CXX" in env and "clang" in os.path.basename(env["CXX"]): + # Convenience check to enforce the use_llvm overrides when CXX is clang(++) + env["use_llvm"] = True + + if env["use_llvm"]: + if "clang++" not in os.path.basename(env["CXX"]): + env["CC"] = "clang" + env["CXX"] = "clang++" + env.extra_suffix = ".llvm" + env.extra_suffix + + if env["use_lld"]: + if env["use_llvm"]: + env.Append(LINKFLAGS=["-fuse-ld=lld"]) + if env["use_thinlto"]: + # A convenience so you don't need to write use_lto too when using SCons + env["use_lto"] = True + else: + print("Using LLD with GCC is not supported yet, try compiling with 'use_llvm=yes'.") + sys.exit(255) + + if env["use_ubsan"] or env["use_asan"] or env["use_lsan"] or env["use_tsan"] or env["use_msan"]: + env.extra_suffix += "s" + + if env["use_ubsan"]: + env.Append( + CCFLAGS=[ + "-fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin" + ] + ) + + if env["use_llvm"]: + env.Append( + CCFLAGS=[ + "-fsanitize=nullability-return,nullability-arg,function,nullability-assign,implicit-integer-sign-change,implicit-signed-integer-truncation,implicit-unsigned-integer-truncation" + ] + ) + else: + env.Append(CCFLAGS=["-fsanitize=bounds-strict"]) + env.Append(LINKFLAGS=["-fsanitize=undefined"]) + + if env["use_asan"]: + env.Append(CCFLAGS=["-fsanitize=address,pointer-subtract,pointer-compare"]) + env.Append(LINKFLAGS=["-fsanitize=address"]) + + if env["use_lsan"]: + env.Append(CCFLAGS=["-fsanitize=leak"]) + env.Append(LINKFLAGS=["-fsanitize=leak"]) + + if env["use_tsan"]: + env.Append(CCFLAGS=["-fsanitize=thread"]) + env.Append(LINKFLAGS=["-fsanitize=thread"]) + + if env["use_msan"]: + env.Append(CCFLAGS=["-fsanitize=memory"]) + env.Append(LINKFLAGS=["-fsanitize=memory"]) + + if env["use_lto"]: + if not env["use_llvm"] and env.GetOption("num_jobs") > 1: + env.Append(CCFLAGS=["-flto"]) + env.Append(LINKFLAGS=["-flto=" + str(env.GetOption("num_jobs"))]) + else: + if env["use_lld"] and env["use_thinlto"]: + env.Append(CCFLAGS=["-flto=thin"]) + env.Append(LINKFLAGS=["-flto=thin"]) + else: + env.Append(CCFLAGS=["-flto"]) + env.Append(LINKFLAGS=["-flto"]) + + if not env["use_llvm"]: + env["RANLIB"] = "gcc-ranlib" + env["AR"] = "gcc-ar" + + env.Append(CCFLAGS=["-pipe"]) + env.Append(LINKFLAGS=["-pipe"]) + + # Check for gcc version >= 6 before adding -no-pie + version = get_compiler_version(env) or [-1, -1] + if using_gcc(env): + if version[0] >= 6: + env.Append(CCFLAGS=["-fpie"]) + env.Append(LINKFLAGS=["-no-pie"]) + # Do the same for clang should be fine with Clang 4 and higher + if using_clang(env): + if version[0] >= 4: + env.Append(CCFLAGS=["-fpie"]) + env.Append(LINKFLAGS=["-no-pie"]) + + ## Dependencies + + # FIXME: Check for existence of the libs before parsing their flags with pkg-config + + # freetype depends on libpng and zlib, so bundling one of them while keeping others + # as shared libraries leads to weird issues + if env["builtin_freetype"] or env["builtin_libpng"] or env["builtin_zlib"]: + env["builtin_freetype"] = True + env["builtin_libpng"] = True + env["builtin_zlib"] = True + + if not env["builtin_freetype"]: + env.ParseConfig("pkg-config freetype2 --cflags --libs") + + if not env["builtin_libpng"]: + env.ParseConfig("pkg-config libpng16 --cflags --libs") + + if not env["builtin_bullet"]: + # We need at least version 2.89 + import subprocess + + bullet_version = subprocess.check_output(["pkg-config", "bullet", "--modversion"]).strip() + if str(bullet_version) < "2.89": + # Abort as system bullet was requested but too old + print( + "Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format( + bullet_version, "2.89" + ) + ) + sys.exit(255) + env.ParseConfig("pkg-config bullet --cflags --libs") + + if False: # not env['builtin_assimp']: + # FIXME: Add min version check + env.ParseConfig("pkg-config assimp --cflags --libs") + + if not env["builtin_enet"]: + env.ParseConfig("pkg-config libenet --cflags --libs") + + if not env["builtin_squish"]: + env.ParseConfig("pkg-config libsquish --cflags --libs") + + if not env["builtin_zstd"]: + env.ParseConfig("pkg-config libzstd --cflags --libs") + + # Sound and video libraries + # Keep the order as it triggers chained dependencies (ogg needed by others, etc.) + + if not env["builtin_libtheora"]: + env["builtin_libogg"] = False # Needed to link against system libtheora + env["builtin_libvorbis"] = False # Needed to link against system libtheora + env.ParseConfig("pkg-config theora theoradec --cflags --libs") + else: + list_of_x86 = ["x86_64", "x86", "i386", "i586"] + if any(platform.machine() in s for s in list_of_x86): + env["x86_libtheora_opt_gcc"] = True + + if not env["builtin_libvpx"]: + env.ParseConfig("pkg-config vpx --cflags --libs") + + if not env["builtin_libvorbis"]: + env["builtin_libogg"] = False # Needed to link against system libvorbis + env.ParseConfig("pkg-config vorbis vorbisfile --cflags --libs") + + if not env["builtin_opus"]: + env["builtin_libogg"] = False # Needed to link against system opus + env.ParseConfig("pkg-config opus opusfile --cflags --libs") + + if not env["builtin_libogg"]: + env.ParseConfig("pkg-config ogg --cflags --libs") + + if not env["builtin_libwebp"]: + env.ParseConfig("pkg-config libwebp --cflags --libs") + + if not env["builtin_mbedtls"]: + # mbedTLS does not provide a pkgconfig config yet. See https://github.com/ARMmbed/mbedtls/issues/228 + env.Append(LIBS=["mbedtls", "mbedcrypto", "mbedx509"]) + + if not env["builtin_wslay"]: + env.ParseConfig("pkg-config libwslay --cflags --libs") + + if not env["builtin_miniupnpc"]: + # No pkgconfig file so far, hardcode default paths. + env.Prepend(CPPPATH=["/usr/include/miniupnpc"]) + env.Append(LIBS=["miniupnpc"]) + + # On Linux wchar_t should be 32-bits + # 16-bit library shouldn't be required due to compiler optimisations + if not env["builtin_pcre2"]: + env.ParseConfig("pkg-config libpcre2-32 --cflags --libs") + + # Embree is only used in tools build on x86_64 and aarch64. + if env["tools"] and not env["builtin_embree"] and is64: + # No pkgconfig file so far, hardcode expected lib name. + env.Append(LIBS=["embree3"]) + + ## Flags + + # Linkflags below this line should typically stay the last ones + if not env["builtin_zlib"]: + env.ParseConfig("pkg-config zlib --cflags --libs") + + env.Prepend(CPPPATH=["#platform/egl"]) + env.Append(CPPDEFINES=["UNIX_ENABLED", "OPENGL_ENABLED", "GLES_ENABLED", "EGL_ENABLED", "EGL_NO_X11"]) + env.Append(LIBS=["OpenGL", "EGL", "pthread"]) + + if platform.system() == "Linux": + env.Append(LIBS=["dl"]) + + if platform.system().find("BSD") >= 0: + env["execinfo"] = True + + if env["execinfo"]: + env.Append(LIBS=["execinfo"]) + + if not env["tools"]: + import subprocess + import re + + linker_version_str = subprocess.check_output([env.subst(env["LINK"]), "-Wl,--version"]).decode("utf-8") + gnu_ld_version = re.search("^GNU ld [^$]*(\d+\.\d+)$", linker_version_str, re.MULTILINE) + if not gnu_ld_version: + print( + "Warning: Creating template binaries enabled for PCK embedding is currently only supported with GNU ld" + ) + else: + if float(gnu_ld_version.group(1)) >= 2.30: + env.Append(LINKFLAGS=["-T", "platform/x11/pck_embed.ld"]) + else: + env.Append(LINKFLAGS=["-T", "platform/x11/pck_embed.legacy.ld"]) + + ## Cross-compilation + + if is64 and env["bits"] == "32": + env.Append(CCFLAGS=["-m32"]) + env.Append(LINKFLAGS=["-m32", "-L/usr/lib/i386-linux-gnu"]) + elif not is64 and env["bits"] == "64": + env.Append(CCFLAGS=["-m64"]) + env.Append(LINKFLAGS=["-m64", "-L/usr/lib/i686-linux-gnu"]) + + # Link those statically for portability + if env["use_static_cpp"]: + env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"]) + if env["use_llvm"]: + env["LINKCOM"] = env["LINKCOM"] + " -l:libatomic.a" + + else: + if env["use_llvm"]: + env.Append(LIBS=["atomic"]) diff --git a/platform/egl/export/export.cpp b/platform/egl/export/export.cpp new file mode 100644 index 0000000000000..160bef437aba8 --- /dev/null +++ b/platform/egl/export/export.cpp @@ -0,0 +1,169 @@ +/*************************************************************************/ +/* export.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "export.h" + +#include "core/os/file_access.h" +#include "editor/editor_export.h" +#include "platform/egl/logo.gen.h" +#include "scene/resources/texture.h" + +static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size); + +void register_egl_exporter() { + + Ref platform; + platform.instance(); + + Ref img = memnew(Image(_egl_logo)); + Ref logo; + logo.instance(); + logo->create_from_image(img); + platform->set_logo(logo); + platform->set_name("Linux/EGL"); + platform->set_extension("x86"); + platform->set_extension("x86_64", "binary_format/64_bits"); + platform->set_release_32("linux_egl_32_release"); + platform->set_debug_32("linux_egl_32_debug"); + platform->set_release_64("linux_egl_64_release"); + platform->set_debug_64("linux_egl_64_debug"); + platform->set_os_name("EGL"); + platform->set_chmod_flags(0755); + platform->set_fixup_embedded_pck_func(&fixup_embedded_pck); + + EditorExport::get_singleton()->add_export_platform(platform); +} + +static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) { + + // Patch the header of the "pck" section in the ELF file so that it corresponds to the embedded data + + FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE); + if (!f) { + return ERR_CANT_OPEN; + } + + // Read and check ELF magic number + { + uint32_t magic = f->get_32(); + if (magic != 0x464c457f) { // 0x7F + "ELF" + f->close(); + return ERR_FILE_CORRUPT; + } + } + + // Read program architecture bits from class field + + int bits = f->get_8() * 32; + + if (bits == 32 && p_embedded_size >= 0x100000000) { + f->close(); + ERR_FAIL_V_MSG(ERR_INVALID_DATA, "32-bit executables cannot have embedded data >= 4 GiB."); + } + + // Get info about the section header table + + int64_t section_table_pos; + int64_t section_header_size; + if (bits == 32) { + section_header_size = 40; + f->seek(0x20); + section_table_pos = f->get_32(); + f->seek(0x30); + } else { // 64 + section_header_size = 64; + f->seek(0x28); + section_table_pos = f->get_64(); + f->seek(0x3c); + } + int num_sections = f->get_16(); + int string_section_idx = f->get_16(); + + // Load the strings table + uint8_t *strings; + { + // Jump to the strings section header + f->seek(section_table_pos + string_section_idx * section_header_size); + + // Read strings data size and offset + int64_t string_data_pos; + int64_t string_data_size; + if (bits == 32) { + f->seek(f->get_position() + 0x10); + string_data_pos = f->get_32(); + string_data_size = f->get_32(); + } else { // 64 + f->seek(f->get_position() + 0x18); + string_data_pos = f->get_64(); + string_data_size = f->get_64(); + } + + // Read strings data + f->seek(string_data_pos); + strings = (uint8_t *)memalloc(string_data_size); + if (!strings) { + f->close(); + return ERR_OUT_OF_MEMORY; + } + f->get_buffer(strings, string_data_size); + } + + // Search for the "pck" section + + bool found = false; + for (int i = 0; i < num_sections; ++i) { + + int64_t section_header_pos = section_table_pos + i * section_header_size; + f->seek(section_header_pos); + + uint32_t name_offset = f->get_32(); + if (strcmp((char *)strings + name_offset, "pck") == 0) { + // "pck" section found, let's patch! + + if (bits == 32) { + f->seek(section_header_pos + 0x10); + f->store_32(p_embedded_start); + f->store_32(p_embedded_size); + } else { // 64 + f->seek(section_header_pos + 0x18); + f->store_64(p_embedded_start); + f->store_64(p_embedded_size); + } + + found = true; + break; + } + } + + memfree(strings); + f->close(); + + return found ? OK : ERR_FILE_CORRUPT; +} diff --git a/platform/egl/export/export.h b/platform/egl/export/export.h new file mode 100644 index 0000000000000..185f03d586af1 --- /dev/null +++ b/platform/egl/export/export.h @@ -0,0 +1,36 @@ +/*************************************************************************/ +/* export.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef EGL_EXPORT_H +#define EGL_EXPORT_H + +void register_egl_exporter(); + +#endif // EGL_EXPORT_H diff --git a/platform/egl/godot_egl.cpp b/platform/egl/godot_egl.cpp new file mode 100644 index 0000000000000..55f480cec9e13 --- /dev/null +++ b/platform/egl/godot_egl.cpp @@ -0,0 +1,67 @@ +/*************************************************************************/ +/* godot_egl.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include +#include +#include +#include + +#include "main/main.h" +#include "os_egl.h" + +int main(int argc, char *argv[]) { + + OS_EGL os; + + setlocale(LC_CTYPE, ""); + + char *cwd = (char *)malloc(PATH_MAX); + ERR_FAIL_COND_V(!cwd, ERR_OUT_OF_MEMORY); + char *ret = getcwd(cwd, PATH_MAX); + + Error err = Main::setup(argv[0], argc - 1, &argv[1]); + if (err != OK) { + free(cwd); + return 255; + } + + if (Main::start()) + os.run(); // it is actually the OS that decides how to run + Main::cleanup(); + + if (ret) { // Previous getcwd was successful + if (chdir(cwd) != 0) { + ERR_PRINT("Couldn't return to previous working directory."); + } + } + free(cwd); + + return os.get_exit_code(); +} diff --git a/platform/egl/logo.png b/platform/egl/logo.png new file mode 100644 index 0000000000000..078654b757f27 Binary files /dev/null and b/platform/egl/logo.png differ diff --git a/platform/egl/os_egl.cpp b/platform/egl/os_egl.cpp new file mode 100644 index 0000000000000..024d7c3195c22 --- /dev/null +++ b/platform/egl/os_egl.cpp @@ -0,0 +1,817 @@ +/*************************************************************************/ +/* os_egl.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "os_egl.h" + +#include "core/os/dir_access.h" +#include "core/print_string.h" +#include "drivers/gles2/rasterizer_gles2.h" +#include "drivers/gles3/rasterizer_gles3.h" +#include "main/main.h" +#include "servers/visual/visual_server_raster.h" +#include "servers/visual/visual_server_wrap_mt.h" + +#ifdef HAVE_MNTENT +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +//stupid linux.h +#ifdef KEY_TAB +#undef KEY_TAB +#endif + +static const double abs_resolution_mult = 10000.0; +static const double abs_resolution_range_mult = 10.0; + +void OS_EGL::initialize_core() { + + crash_handler.initialize(); + + OS_Unix::initialize_core(); +} + +int OS_EGL::get_current_video_driver() const { + return video_driver_index; +} + +Error OS_EGL::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { + last_button_state = 0; + + last_click_ms = 0; + last_click_button_index = -1; + last_click_pos = Point2(-100, -100); + args = OS::get_singleton()->get_cmdline_args(); + current_videomode = p_desired; + main_loop = NULL; + last_timestamp = 0; + last_mouse_pos_valid = false; + +// maybe contextgl wants to be in charge of creating the window +#if defined(OPENGL_ENABLED) + ContextGL_EGL::ContextType opengl_api_type = ContextGL_EGL::GLES_3_0_COMPATIBLE; + + if (p_video_driver == VIDEO_DRIVER_GLES2) { + opengl_api_type = ContextGL_EGL::GLES_2_0_COMPATIBLE; + } + + bool editor = Engine::get_singleton()->is_editor_hint(); + bool gl_initialization_error = false; + + context_gl = NULL; + while (!context_gl) { + context_gl = memnew(ContextGL_EGL(current_videomode, opengl_api_type)); + + if (context_gl->initialize(p_desired.width, p_desired.height) != OK) { + memdelete(context_gl); + context_gl = NULL; + + if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2") || editor) { + if (p_video_driver == VIDEO_DRIVER_GLES2) { + gl_initialization_error = true; + break; + } + + p_video_driver = VIDEO_DRIVER_GLES2; + opengl_api_type = ContextGL_EGL::GLES_2_0_COMPATIBLE; + } else { + gl_initialization_error = true; + break; + } + } + } + + while (true) { + if (opengl_api_type == ContextGL_EGL::GLES_3_0_COMPATIBLE) { + if (RasterizerGLES3::is_viable() == OK) { + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); + break; + } else { + if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2") || editor) { + p_video_driver = VIDEO_DRIVER_GLES2; + opengl_api_type = ContextGL_EGL::GLES_2_0_COMPATIBLE; + continue; + } else { + gl_initialization_error = true; + break; + } + } + } + + if (opengl_api_type == ContextGL_EGL::GLES_2_0_COMPATIBLE) { + if (RasterizerGLES2::is_viable() == OK) { + RasterizerGLES2::register_config(); + RasterizerGLES2::make_current(); + break; + } else { + gl_initialization_error = true; + break; + } + } + } + + if (gl_initialization_error) { + OS::get_singleton()->alert("Your video card driver does not support any of the supported OpenGL versions.\n" + "Please update your drivers or if you have a very old or integrated GPU, upgrade it.\n" + "Alternatively, you can force software rendering by running Godot with the `LIBGL_ALWAYS_SOFTWARE=1`\n" + "environment variable set, but this will be very slow.", + "Unable to initialize Video driver"); + return ERR_UNAVAILABLE; + } + + video_driver_index = p_video_driver; + + context_gl->set_use_vsync(current_videomode.use_vsync); + +#endif + + visual_server = memnew(VisualServerRaster); + if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) { + visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD)); + } + + if (current_videomode.maximized) { + current_videomode.maximized = false; + set_window_maximized(true); + // borderless fullscreen window mode + } else if (current_videomode.fullscreen) { + current_videomode.fullscreen = false; + set_window_fullscreen(true); + } else if (current_videomode.borderless_window) { + } + + // disable resizable window + if (!current_videomode.resizable && !current_videomode.fullscreen) { + } + + if (current_videomode.always_on_top) { + current_videomode.always_on_top = false; + set_window_always_on_top(true); + } + + ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE); + + im_active = false; + im_position = Vector2(); + + visual_server->init(); + + AudioDriverManager::initialize(p_audio_driver); + + input = memnew(InputDefault); + + window_has_focus = true; // Set focus to true at init + + if (p_desired.layered) { + set_window_per_pixel_transparency_enabled(true); + } + + return OK; +} + +void OS_EGL::set_ime_active(const bool p_active) { + im_active = p_active; +} + +void OS_EGL::set_ime_position(const Point2 &p_pos) { + im_position = p_pos; +} + +String OS_EGL::get_unique_id() const { + + static String machine_id; + if (machine_id.empty()) { + if (FileAccess *f = FileAccess::open("/etc/machine-id", FileAccess::READ)) { + while (machine_id.empty() && !f->eof_reached()) { + machine_id = f->get_line().strip_edges(); + } + f->close(); + memdelete(f); + } + } + return machine_id; +} + +void OS_EGL::finalize() { + if (main_loop) + memdelete(main_loop); + main_loop = NULL; + + /* + if (debugger_connection_console) { + memdelete(debugger_connection_console); + } + */ + + memdelete(input); + visual_server->finish(); + memdelete(visual_server); + //memdelete(rasterizer); + +#if defined(OPENGL_ENABLED) + memdelete(context_gl); +#endif + args.clear(); +} + +void OS_EGL::set_mouse_mode(MouseMode p_mode) { +} + +void OS_EGL::warp_mouse_position(const Point2 &p_to) { +} + +OS::MouseMode OS_EGL::get_mouse_mode() const { + return mouse_mode; +} + +int OS_EGL::get_mouse_button_state() const { + return last_button_state; +} + +Point2 OS_EGL::get_mouse_position() const { + return last_mouse_pos; +} + +bool OS_EGL::get_window_per_pixel_transparency_enabled() const { + + if (!is_layered_allowed()) return false; + return layered_window; +} + +void OS_EGL::set_window_per_pixel_transparency_enabled(bool p_enabled) { + + if (!is_layered_allowed()) return; + if (layered_window != p_enabled) { + if (p_enabled) { + layered_window = true; + } else { + layered_window = false; + } + } +} + +void OS_EGL::set_window_title(const String &p_title) { +} + +void OS_EGL::set_window_mouse_passthrough(const PoolVector2Array &p_region) { +} + +void OS_EGL::set_video_mode(const VideoMode &p_video_mode, int p_screen) { +} + +OS::VideoMode OS_EGL::get_video_mode(int p_screen) const { + return current_videomode; +} + +void OS_EGL::get_fullscreen_mode_list(List *p_list, int p_screen) const { +} + +void OS_EGL::set_wm_fullscreen(bool p_enabled) { +} + +void OS_EGL::set_wm_above(bool p_enabled) { +} + +int OS_EGL::get_screen_count() const { + return 1; +} + +int OS_EGL::get_current_screen() const { + return 0; +} + +void OS_EGL::set_current_screen(int p_screen) { +} + +Point2 OS_EGL::get_screen_position(int p_screen) const { + return Point2i(0, 0); +} + +Size2 OS_EGL::get_screen_size(int p_screen) const { + return Point2i(current_videomode.width, current_videomode.height); +} + +int OS_EGL::get_screen_dpi(int p_screen) const { + return 96; +} + +Point2 OS_EGL::get_window_position() const { + return Point2i(0, 0); +} + +void OS_EGL::set_window_position(const Point2 &p_position) { +} + +Size2 OS_EGL::get_window_size() const { + return Point2i(current_videomode.width, current_videomode.height); +} + +Size2 OS_EGL::get_real_window_size() const { + return Point2i(current_videomode.width, current_videomode.height); +} + +Size2 OS_EGL::get_max_window_size() const { + return max_size; +} + +Size2 OS_EGL::get_min_window_size() const { + return min_size; +} + +void OS_EGL::set_min_window_size(const Size2 p_size) { + min_size = p_size; +} + +void OS_EGL::set_max_window_size(const Size2 p_size) { + max_size = p_size; +} + +void OS_EGL::set_window_size(const Size2 p_size) { + context_gl->set_buffer_size(p_size.width, p_size.height); +// glViewport(0, 0, p_size.width, p_size.height); +// glScissor(0, 0, p_size.width, p_size.height); + current_videomode.width = p_size.width; + current_videomode.height = p_size.height; +} + +void OS_EGL::set_window_fullscreen(bool p_enabled) { +} + +bool OS_EGL::is_window_fullscreen() const { + return current_videomode.fullscreen; +} + +void OS_EGL::set_window_resizable(bool p_enabled) { +} + +bool OS_EGL::is_window_resizable() const { + return current_videomode.resizable; +} + +void OS_EGL::set_window_minimized(bool p_enabled) { +} + +bool OS_EGL::is_window_minimized() const { + return false; +} + +void OS_EGL::set_window_maximized(bool p_enabled) { +} + +bool OS_EGL::is_window_maximize_allowed() const { + return true; +} + +bool OS_EGL::is_window_maximized() const { + return false; +} + +void OS_EGL::set_window_always_on_top(bool p_enabled) { + current_videomode.always_on_top = p_enabled; +} + +bool OS_EGL::is_window_always_on_top() const { + return current_videomode.always_on_top; +} + +bool OS_EGL::is_window_focused() const { + return window_focused; +} + +void OS_EGL::set_borderless_window(bool p_borderless) { +} + +bool OS_EGL::get_borderless_window() { + return false; +} + +void OS_EGL::request_attention() { +} + +void *OS_EGL::get_native_handle(int p_handle_type) { + switch (p_handle_type) { + case APPLICATION_HANDLE: + case DISPLAY_HANDLE: + case WINDOW_HANDLE: + case WINDOW_VIEW: + case OPENGL_CONTEXT: + default: return NULL; + } +} + +MainLoop *OS_EGL::get_main_loop() const { + + return main_loop; +} + +void OS_EGL::delete_main_loop() { + if (main_loop) + memdelete(main_loop); + main_loop = NULL; +} + +void OS_EGL::set_main_loop(MainLoop *p_main_loop) { + main_loop = p_main_loop; + input->set_main_loop(p_main_loop); +} + +bool OS_EGL::can_draw() const { + return !minimized; +}; + +void OS_EGL::set_clipboard(const String &p_text) { +}; + +String OS_EGL::get_clipboard() const { + return ""; +} + +String OS_EGL::get_name() const { + + return "X11"; +} + +Error OS_EGL::shell_open(String p_uri) { + Error ok; + int err_code; + List args; + args.push_back(p_uri); + + // Agnostic + ok = execute("xdg-open", args, true, NULL, NULL, &err_code); + if (ok == OK && !err_code) { + return OK; + } else if (err_code == 2) { + return ERR_FILE_NOT_FOUND; + } + // GNOME + args.push_front("open"); // The command is `gio open`, so we need to add it to args + ok = execute("gio", args, true, NULL, NULL, &err_code); + if (ok == OK && !err_code) { + return OK; + } else if (err_code == 2) { + return ERR_FILE_NOT_FOUND; + } + args.pop_front(); + ok = execute("gvfs-open", args, true, NULL, NULL, &err_code); + if (ok == OK && !err_code) { + return OK; + } else if (err_code == 2) { + return ERR_FILE_NOT_FOUND; + } + // KDE + ok = execute("kde-open5", args, true, NULL, NULL, &err_code); + if (ok == OK && !err_code) { + return OK; + } + ok = execute("kde-open", args, true, NULL, NULL, &err_code); + return !err_code ? ok : FAILED; +} + +bool OS_EGL::_check_internal_feature_support(const String &p_feature) { + + return p_feature == "pc"; +} + +String OS_EGL::get_config_path() const { + + if (has_environment("XDG_CONFIG_HOME")) { + return get_environment("XDG_CONFIG_HOME"); + } else if (has_environment("HOME")) { + return get_environment("HOME").plus_file(".config"); + } else { + return "."; + } +} + +String OS_EGL::get_data_path() const { + + if (has_environment("XDG_DATA_HOME")) { + return get_environment("XDG_DATA_HOME"); + } else if (has_environment("HOME")) { + return get_environment("HOME").plus_file(".local/share"); + } else { + return get_config_path(); + } +} + +String OS_EGL::get_cache_path() const { + + if (has_environment("XDG_CACHE_HOME")) { + return get_environment("XDG_CACHE_HOME"); + } else if (has_environment("HOME")) { + return get_environment("HOME").plus_file(".cache"); + } else { + return get_config_path(); + } +} + +String OS_EGL::get_system_dir(SystemDir p_dir, bool p_shared_storage) const { + String xdgparam; + + switch (p_dir) { + case SYSTEM_DIR_DESKTOP: { + + xdgparam = "DESKTOP"; + } break; + case SYSTEM_DIR_DCIM: { + + xdgparam = "PICTURES"; + + } break; + case SYSTEM_DIR_DOCUMENTS: { + + xdgparam = "DOCUMENTS"; + + } break; + case SYSTEM_DIR_DOWNLOADS: { + + xdgparam = "DOWNLOAD"; + + } break; + case SYSTEM_DIR_MOVIES: { + + xdgparam = "VIDEOS"; + + } break; + case SYSTEM_DIR_MUSIC: { + + xdgparam = "MUSIC"; + + } break; + case SYSTEM_DIR_PICTURES: { + + xdgparam = "PICTURES"; + + } break; + case SYSTEM_DIR_RINGTONES: { + + xdgparam = "MUSIC"; + + } break; + } + + String pipe; + List arg; + arg.push_back(xdgparam); + Error err = const_cast(this)->execute("xdg-user-dir", arg, true, NULL, &pipe); + if (err != OK) + return "."; + return pipe.strip_edges(); +} + +void OS_EGL::move_window_to_foreground() { +} + +void OS_EGL::set_cursor_shape(CursorShape p_shape) { +} + +OS::CursorShape OS_EGL::get_cursor_shape() const { + return CURSOR_ARROW; +} + +void OS_EGL::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +} + +void OS_EGL::release_rendering_thread() { + +#if defined(OPENGL_ENABLED) + context_gl->release_current(); +#endif +} + +void OS_EGL::make_rendering_thread() { + +#if defined(OPENGL_ENABLED) + context_gl->make_current(); +#endif +} + +void OS_EGL::swap_buffers() { + +#if defined(OPENGL_ENABLED) + context_gl->swap_buffers(); +#endif +} + +void OS_EGL::alert(const String &p_alert, const String &p_title) { + + if (is_no_window_mode_enabled()) { + print_line("ALERT: " + p_title + ": " + p_alert); + return; + } + + const char *message_programs[] = { "zenity", "kdialog", "Xdialog", "xmessage" }; + + String path = get_environment("PATH"); + Vector path_elems = path.split(":", false); + String program; + + for (int i = 0; i < path_elems.size(); i++) { + for (uint64_t k = 0; k < sizeof(message_programs) / sizeof(char *); k++) { + String tested_path = path_elems[i].plus_file(message_programs[k]); + + if (FileAccess::exists(tested_path)) { + program = tested_path; + break; + } + } + + if (program.length()) + break; + } + + List args; + + if (program.ends_with("zenity")) { + args.push_back("--error"); + args.push_back("--width"); + args.push_back("500"); + args.push_back("--title"); + args.push_back(p_title); + args.push_back("--text"); + args.push_back(p_alert); + } + + if (program.ends_with("kdialog")) { + args.push_back("--error"); + args.push_back(p_alert); + args.push_back("--title"); + args.push_back(p_title); + } + + if (program.ends_with("Xdialog")) { + args.push_back("--title"); + args.push_back(p_title); + args.push_back("--msgbox"); + args.push_back(p_alert); + args.push_back("0"); + args.push_back("0"); + } + + if (program.ends_with("xmessage")) { + args.push_back("-center"); + args.push_back("-title"); + args.push_back(p_title); + args.push_back(p_alert); + } + + if (program.length()) { + execute(program, args, true); + } else { + print_line(p_alert); + } +} + + +void OS_EGL::set_icon(const Ref &p_icon) { +} + +void OS_EGL::force_process_input() { +} + +void OS_EGL::run() { + + force_quit = false; + + if (!main_loop) + return; + + main_loop->init(); + + //uint64_t last_ticks=get_ticks_usec(); + + //int frames=0; + //uint64_t frame=0; + + while (!force_quit) { + if (Main::iteration()) + break; + }; + + main_loop->finish(); +} + +bool OS_EGL::is_joy_known(int p_device) { + return input->is_joy_mapped(p_device); +} + +String OS_EGL::get_joy_guid(int p_device) const { + return input->get_joy_guid_remapped(p_device); +} + +void OS_EGL::_set_use_vsync(bool p_enable) { +#if defined(OPENGL_ENABLED) + if (context_gl) + context_gl->set_use_vsync(p_enable); +#endif +} +/* +bool OS_EGL::is_vsync_enabled() const { + + if (context_gl) + return context_gl->is_using_vsync(); + + return true; +} +*/ +void OS_EGL::set_context(int p_context) { +} + +OS::PowerState OS_EGL::get_power_state() { + return POWERSTATE_NO_BATTERY; +} + +int OS_EGL::get_power_seconds_left() { + return -1; +} + +int OS_EGL::get_power_percent_left() { + return -1; +} + +void OS_EGL::disable_crash_handler() { + crash_handler.disable(); +} + +bool OS_EGL::is_disable_crash_handler() const { + return crash_handler.is_disabled(); +} + +Error OS_EGL::move_to_trash(const String &p_path) { + DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Error err = dir_access->remove(p_path); + memdelete(dir_access); + return err; +} + +OS::LatinKeyboardVariant OS_EGL::get_latin_keyboard_variant() const { + return LATIN_KEYBOARD_QWERTY; +} + +int OS_EGL::keyboard_get_layout_count() const { + return 0; +} + +int OS_EGL::keyboard_get_current_layout() const { + return 0; +} + +void OS_EGL::keyboard_set_current_layout(int p_index) { +} + +String OS_EGL::keyboard_get_layout_language(int p_index) const { + return ""; +} + +String OS_EGL::keyboard_get_layout_name(int p_index) const { + return ""; +} + + +OS_EGL::OS_EGL() { + layered_window = false; + minimized = false; + window_focused = true; + mouse_mode = MOUSE_MODE_VISIBLE; + last_position_before_fs = Vector2(); +} diff --git a/platform/egl/os_egl.h b/platform/egl/os_egl.h new file mode 100644 index 0000000000000..d3de5e7a7b6c5 --- /dev/null +++ b/platform/egl/os_egl.h @@ -0,0 +1,229 @@ +/*************************************************************************/ +/* os_egl.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OS_EGL_H +#define OS_EGL_H + +#include "context_gl_egl.h" +#include "core/local_vector.h" +#include "core/os/input.h" +#include "crash_handler_egl.h" +#include "drivers/alsa/audio_driver_alsa.h" +#include "drivers/alsamidi/midi_driver_alsamidi.h" +#include "drivers/pulseaudio/audio_driver_pulseaudio.h" +#include "drivers/unix/os_unix.h" +#include "main/input_default.h" +#include "servers/audio_server.h" +#include "servers/visual/rasterizer.h" +#include "servers/visual_server.h" + +class OS_EGL : public OS_Unix { + +#if defined(OPENGL_ENABLED) + ContextGL_EGL *context_gl; +#endif + //Rasterizer *rasterizer; + VisualServer *visual_server; + VideoMode current_videomode; + List args; + MainLoop *main_loop; + unsigned long last_timestamp; + + // IME + bool im_active; + Vector2 im_position; + Vector2 last_position_before_fs; + + Size2 min_size; + Size2 max_size; + + Point2 last_mouse_pos; + bool last_mouse_pos_valid; + Point2i last_click_pos; + uint64_t last_click_ms; + int last_click_button_index; + uint32_t last_button_state; + + MouseMode mouse_mode; + Point2i center; + + mutable Mutex events_mutex; + + virtual void delete_main_loop(); + + bool force_quit; + bool minimized; + bool window_has_focus; + bool do_mouse_warp; + + const char *cursor_theme; + int cursor_size; + + InputDefault *input; + + bool layered_window; + + CrashHandler crash_handler; + + int video_driver_index; + bool maximized; + bool window_focused; + //void set_wm_border(bool p_enabled); + void set_wm_fullscreen(bool p_enabled); + void set_wm_above(bool p_enabled); + +protected: + virtual int get_current_video_driver() const; + + virtual void initialize_core(); + virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); + virtual void finalize(); + + virtual void set_main_loop(MainLoop *p_main_loop); + + bool is_window_maximize_allowed() const; + +public: + virtual String get_name() const; + + virtual void set_cursor_shape(CursorShape p_shape); + virtual CursorShape get_cursor_shape() const; + virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); + + void set_mouse_mode(MouseMode p_mode); + MouseMode get_mouse_mode() const; + + virtual void warp_mouse_position(const Point2 &p_to); + virtual Point2 get_mouse_position() const; + virtual int get_mouse_button_state() const; + virtual void set_window_title(const String &p_title); + virtual void set_window_mouse_passthrough(const PoolVector2Array &p_region); + + virtual void set_icon(const Ref &p_icon); + + virtual MainLoop *get_main_loop() const; + + virtual bool can_draw() const; + + virtual void set_clipboard(const String &p_text); + virtual String get_clipboard() const; + + virtual void release_rendering_thread(); + virtual void make_rendering_thread(); + virtual void swap_buffers(); + + virtual String get_config_path() const; + virtual String get_data_path() const; + virtual String get_cache_path() const; + + virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const; + + virtual Error shell_open(String p_uri); + + virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0); + virtual VideoMode get_video_mode(int p_screen = 0) const; + virtual void get_fullscreen_mode_list(List *p_list, int p_screen = 0) const; + + virtual int get_screen_count() const; + virtual int get_current_screen() const; + virtual void set_current_screen(int p_screen); + virtual Point2 get_screen_position(int p_screen = -1) const; + virtual Size2 get_screen_size(int p_screen = -1) const; + virtual int get_screen_dpi(int p_screen = -1) const; + virtual Point2 get_window_position() const; + virtual void set_window_position(const Point2 &p_position); + virtual Size2 get_window_size() const; + virtual Size2 get_real_window_size() const; + virtual Size2 get_max_window_size() const; + virtual Size2 get_min_window_size() const; + virtual void set_min_window_size(const Size2 p_size); + virtual void set_max_window_size(const Size2 p_size); + virtual void set_window_size(const Size2 p_size); + virtual void set_window_fullscreen(bool p_enabled); + virtual bool is_window_fullscreen() const; + virtual void set_window_resizable(bool p_enabled); + virtual bool is_window_resizable() const; + virtual void set_window_minimized(bool p_enabled); + virtual bool is_window_minimized() const; + virtual void set_window_maximized(bool p_enabled); + virtual bool is_window_maximized() const; + virtual void set_window_always_on_top(bool p_enabled); + virtual bool is_window_always_on_top() const; + virtual bool is_window_focused() const; + virtual void request_attention(); + virtual void *get_native_handle(int p_handle_type); + + virtual void set_borderless_window(bool p_borderless); + virtual bool get_borderless_window(); + + virtual bool get_window_per_pixel_transparency_enabled() const; + virtual void set_window_per_pixel_transparency_enabled(bool p_enabled); + + virtual void set_ime_active(const bool p_active); + virtual void set_ime_position(const Point2 &p_pos); + + virtual String get_unique_id() const; + + virtual void move_window_to_foreground(); + virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); + + virtual bool is_joy_known(int p_device); + virtual String get_joy_guid(int p_device) const; + + virtual void set_context(int p_context); + + virtual void _set_use_vsync(bool p_enable); + //virtual bool is_vsync_enabled() const; + + virtual OS::PowerState get_power_state(); + virtual int get_power_seconds_left(); + virtual int get_power_percent_left(); + + virtual bool _check_internal_feature_support(const String &p_feature); + + virtual void force_process_input(); + void run(); + + void disable_crash_handler(); + bool is_disable_crash_handler() const; + + virtual Error move_to_trash(const String &p_path); + + virtual LatinKeyboardVariant get_latin_keyboard_variant() const; + virtual int keyboard_get_layout_count() const; + virtual int keyboard_get_current_layout() const; + virtual void keyboard_set_current_layout(int p_index); + virtual String keyboard_get_layout_language(int p_index) const; + virtual String keyboard_get_layout_name(int p_index) const; + + OS_EGL(); +}; + +#endif diff --git a/platform/egl/pck_embed.ld b/platform/egl/pck_embed.ld new file mode 100644 index 0000000000000..57a1994043b80 --- /dev/null +++ b/platform/egl/pck_embed.ld @@ -0,0 +1,10 @@ +SECTIONS +{ + /* Add a zero-sized section; the exporter will patch it to enclose the data appended to the executable (embedded PCK) */ + pck 0 (INFO) : + { + /* binutils >= 2.30 allow it being zero-sized, but needs something between the braces to keep the section */ + . = ALIGN(8); + } +} +INSERT AFTER .rodata; diff --git a/platform/egl/pck_embed.legacy.ld b/platform/egl/pck_embed.legacy.ld new file mode 100644 index 0000000000000..a23013ba7ae6b --- /dev/null +++ b/platform/egl/pck_embed.legacy.ld @@ -0,0 +1,10 @@ +SECTIONS +{ + /* The exporter will patch this section to enclose the data appended to the executable (embedded PCK) */ + pck 0 (INFO) : AT ( ADDR (.rodata) + SIZEOF (.rodata) ) + { + /* binutils < 2.30 need some actual content for the linker not to discard the section */ + BYTE(0); + } +} +INSERT AFTER .rodata; diff --git a/platform/egl/platform_config.h b/platform/egl/platform_config.h new file mode 100644 index 0000000000000..cdf989fee7a9f --- /dev/null +++ b/platform/egl/platform_config.h @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* platform_config.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef __linux__ +#include +#endif + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +#include // alloca +// FreeBSD and OpenBSD use pthread_set_name_np, while other platforms, +// include NetBSD, use pthread_setname_np. NetBSD's version however requires +// a different format, we handle this directly in thread_posix. +#ifdef __NetBSD__ +#define PTHREAD_NETBSD_SET_NAME +#else +#define PTHREAD_BSD_SET_NAME +#endif +#endif + +#define GLES3_INCLUDE_H "thirdparty/glad/glad/glad.h" +#define GLES2_INCLUDE_H "thirdparty/glad/glad/glad.h" diff --git a/platform/egl/platform_egl_builders.py b/platform/egl/platform_egl_builders.py new file mode 100644 index 0000000000000..4f801d342e14f --- /dev/null +++ b/platform/egl/platform_egl_builders.py @@ -0,0 +1,17 @@ +"""Functions used to generate source files during build time + +All such functions are invoked in a subprocess on Windows to prevent build flakiness. + +""" +import os +from platform_methods import subprocess_main + + +def make_debug_egl(target, source, env): + os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0])) + os.system("strip --strip-debug --strip-unneeded {0}".format(target[0])) + os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0])) + + +if __name__ == "__main__": + subprocess_main(globals()) diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp index ebbba012863ae..c966ccb06cb70 100644 --- a/servers/physics_server.cpp +++ b/servers/physics_server.cpp @@ -796,6 +796,7 @@ void PhysicsServer::_bind_methods() { BIND_ENUM_CONSTANT(BODY_AXIS_ANGULAR_Y); BIND_ENUM_CONSTANT(BODY_AXIS_ANGULAR_Z); + ClassDB::bind_method(D_METHOD("flush_queries"), &PhysicsServer::flush_queries); #endif } diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 7fcd77e6fc131..38df875d3d23e 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -360,8 +360,10 @@ void VisualServerViewport::draw_viewports() { if (vp->viewport_to_screen_rect != Rect2() && (!vp->viewport_render_direct_to_screen || !VSG::rasterizer->is_low_end())) { //copy to screen if set as such +#ifndef EGL_ENABLED VSG::rasterizer->set_current_render_target(RID()); VSG::rasterizer->blit_render_target_to_screen(vp->render_target, vp->viewport_to_screen_rect, vp->viewport_to_screen); +#endif } } diff --git a/thirdparty/glad/glad.c b/thirdparty/glad/glad.c index dc1b8cb697e66..e500e1cf830e1 100644 --- a/thirdparty/glad/glad.c +++ b/thirdparty/glad/glad.c @@ -97,8 +97,12 @@ int open_gl(void) { "/System/Library/Frameworks/OpenGL.framework/OpenGL", "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" }; +#else +#ifdef EGL_ENABLED + static const char *NAMES[] = {"libOpenGL.so.0", "libOpenGL.so"}; #else static const char *NAMES[] = {"libGL.so.1", "libGL.so"}; +#endif #endif unsigned int index = 0; @@ -109,6 +113,9 @@ int open_gl(void) { #if defined(__APPLE__) || defined(__HAIKU__) return 1; #else +#ifdef EGL_ENABLED + return 1; +#endif gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL, "glXGetProcAddressARB"); return gladGetProcAddressPtr != NULL; @@ -133,6 +140,10 @@ void* get_proc(const char *namez) { void* result = NULL; if(libGL == NULL) return NULL; +#if defined(EGL_ENABLED) + return eglGetProcAddress(namez); +#endif + #if !defined(__APPLE__) && !defined(__HAIKU__) if(gladGetProcAddressPtr != NULL) { result = gladGetProcAddressPtr(namez); diff --git a/thirdparty/glad/glad/glad.h b/thirdparty/glad/glad/glad.h index f211e6aa57095..64a1b70fbf7e2 100644 --- a/thirdparty/glad/glad/glad.h +++ b/thirdparty/glad/glad/glad.h @@ -32,6 +32,10 @@ #endif #define __gl_h_ +#if defined(EGL_ENABLED) +#include +#endif + #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) #define APIENTRY __stdcall #endif