// video_fbdev.cc /* * FRT - A Godot platform targeting single board computers * Copyright (c) 2017-2019 Emanuele Fornara * * 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 "frt.h" #include #include "bits/egl_base_context.h" #define FRT_DL_SKIP #include "dl/gles2.gen.h" static bool frt_load_gles(int version) { return frt_load_gles2("libGLESv2.so.2"); } #define FRT_FBDEV_MALI 1 static int probe_fbdev() { return FRT_FBDEV_MALI; } namespace frt { class EGLFBDevContext : public EGLBaseContext { public: virtual void create_surface(const Vec2 &size) = 0; virtual ~EGLFBDevContext() {} }; class EGLMaliContext : public EGLFBDevContext { private: struct { uint16_t width; uint16_t height; } nativewindow; public: void create_surface(const Vec2 &size) { nativewindow.width = size.x; nativewindow.height = size.y; surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)&nativewindow, 0); if (surface == EGL_NO_SURFACE) fatal("video_fbdev: eglCreateWindowSurface failed."); } }; class VideoFBDev : public Video, public ContextGL { private: bool initialized; Vec2 screen_size; Vec2 view_size; EGLFBDevContext *egl; int gl_version; bool vsync; void gles_init() { egl->init(gl_version); egl->create_surface(view_size); egl->make_current(); initialized = true; } public: // Module VideoFBDev() : initialized(false), egl(0), gl_version(2), vsync(true) {} const char *get_id() const { return "video_fbdev"; } bool probe() { if (egl) return true; switch (probe_fbdev()) { case FRT_FBDEV_MALI: egl = new EGLMaliContext(); break; default: fatal("video_fbdev: internal error."); } if (!frt_load_egl("libEGL.so.1")) { delete egl; egl = 0; return false; } screen_size.x = 720; screen_size.y = 480; return true; } void cleanup() { if (initialized) { egl->destroy_surface(); egl->cleanup(); initialized = false; } if (egl) { delete egl; egl = 0; } } // Video Vec2 get_screen_size() const { return screen_size; } Vec2 get_view_size() const { return view_size; } void set_title(const char *title) {} Vec2 move_pointer(const Vec2 &screen) { return screen; } void show_pointer(bool enable) {} ContextGL *create_the_gl_context(int version, Vec2 size) { if (!frt_load_gles(version)) return 0; gl_version = version; view_size = size; return this; } bool provides_quit() { return false; } // ContextGL void release_current() { egl->release_current(); } void make_current() { egl->make_current(); } void swap_buffers() { egl->swap_buffers(); } int get_window_width() { return view_size.x; } int get_window_height() { return view_size.y; } bool initialize() { gles_init(); return true; } void set_use_vsync(bool use) { egl->swap_interval(use ? 1 : 0); vsync = use; } bool is_using_vsync() const { return vsync; } }; FRT_REGISTER(VideoFBDev) } // namespace frt