summaryrefslogtreecommitdiff
path: root/platform/linuxbsd/display_server_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linuxbsd/display_server_x11.cpp')
-rw-r--r--platform/linuxbsd/display_server_x11.cpp579
1 files changed, 455 insertions, 124 deletions
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 212b6762e1..e98d114267 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -34,6 +34,7 @@
#include "core/config/project_settings.h"
#include "core/string/print_string.h"
+#include "core/string/ustring.h"
#include "detect_prime_x11.h"
#include "key_mapping_x11.h"
#include "main/main.h"
@@ -43,6 +44,10 @@
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#endif
+#if defined(GLES3_ENABLED)
+#include "drivers/gles3/rasterizer_gles3.h"
+#endif
+
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@@ -616,7 +621,7 @@ String DisplayServerX11::clipboard_get_primary() const {
Bool DisplayServerX11::_predicate_clipboard_save_targets(Display *display, XEvent *event, XPointer arg) {
if (event->xany.window == *(Window *)arg) {
return (event->type == SelectionRequest) ||
- (event->type == SelectionNotify);
+ (event->type == SelectionNotify);
} else {
return False;
}
@@ -683,35 +688,49 @@ int DisplayServerX11::get_screen_count() const {
return count;
}
-Point2i DisplayServerX11::screen_get_position(int p_screen) const {
- _THREAD_SAFE_METHOD_
+Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const {
+ Rect2i rect(0, 0, 0, 0);
if (p_screen == SCREEN_OF_MAIN_WINDOW) {
p_screen = window_get_current_screen();
}
- // Using Xinerama Extension
- int event_base, error_base;
- const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
- if (!ext_okay) {
- return Point2i(0, 0);
- }
+ ERR_FAIL_COND_V(p_screen < 0, rect);
- int count;
- XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+ // Using Xinerama Extension.
+ int event_base, error_base;
+ if (XineramaQueryExtension(x11_display, &event_base, &error_base)) {
+ int count;
+ XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+
+ // Check if screen is valid.
+ if (p_screen < count) {
+ rect.position.x = xsi[p_screen].x_org;
+ rect.position.y = xsi[p_screen].y_org;
+ rect.size.width = xsi[p_screen].width;
+ rect.size.height = xsi[p_screen].height;
+ } else {
+ ERR_PRINT("Invalid screen index: " + itos(p_screen) + "(count: " + itos(count) + ").");
+ }
- // Check if screen is valid
- ERR_FAIL_INDEX_V(p_screen, count, Point2i(0, 0));
+ if (xsi) {
+ XFree(xsi);
+ }
+ }
- Point2i position = Point2i(xsi[p_screen].x_org, xsi[p_screen].y_org);
+ return rect;
+}
- XFree(xsi);
+Point2i DisplayServerX11::screen_get_position(int p_screen) const {
+ _THREAD_SAFE_METHOD_
- return position;
+ return _screen_get_rect(p_screen).position;
}
Size2i DisplayServerX11::screen_get_size(int p_screen) const {
- return screen_get_usable_rect(p_screen).size;
+ _THREAD_SAFE_METHOD_
+
+ return _screen_get_rect(p_screen).size;
}
Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
@@ -721,21 +740,267 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
p_screen = window_get_current_screen();
}
- // Using Xinerama Extension
- int event_base, error_base;
- const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
- if (!ext_okay) {
- return Rect2i(0, 0, 0, 0);
+ int screen_count = get_screen_count();
+
+ // Check if screen is valid.
+ ERR_FAIL_INDEX_V(p_screen, screen_count, Rect2i(0, 0, 0, 0));
+
+ bool is_multiscreen = screen_count > 1;
+
+ // Use full monitor size as fallback.
+ Rect2i rect = _screen_get_rect(p_screen);
+
+ // There's generally only one screen reported by xlib even in multi-screen setup,
+ // in this case it's just one virtual screen composed of all physical monitors.
+ int x11_screen_count = ScreenCount(x11_display);
+ Window x11_window = RootWindow(x11_display, p_screen < x11_screen_count ? p_screen : 0);
+
+ Atom type;
+ int format = 0;
+ unsigned long remaining = 0;
+
+ // Find active desktop for the root window.
+ unsigned int desktop_index = 0;
+ Atom desktop_prop = XInternAtom(x11_display, "_NET_CURRENT_DESKTOP", True);
+ if (desktop_prop != None) {
+ unsigned long desktop_len = 0;
+ unsigned char *desktop_data = nullptr;
+ if (XGetWindowProperty(x11_display, x11_window, desktop_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &desktop_len, &remaining, &desktop_data) == Success) {
+ if ((format == 32) && (desktop_len > 0) && desktop_data) {
+ desktop_index = (unsigned int)desktop_data[0];
+ }
+ if (desktop_data) {
+ XFree(desktop_data);
+ }
+ }
}
- int count;
- XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+ bool use_simple_method = true;
+
+ // First check for GTK work area, which is more accurate for multi-screen setup.
+ if (is_multiscreen) {
+ // Use already calculated work area when available.
+ Atom gtk_workareas_prop = XInternAtom(x11_display, "_GTK_WORKAREAS", False);
+ if (gtk_workareas_prop != None) {
+ char gtk_workarea_prop_name[32];
+ snprintf(gtk_workarea_prop_name, 32, "_GTK_WORKAREAS_D%d", desktop_index);
+ Atom gtk_workarea_prop = XInternAtom(x11_display, gtk_workarea_prop_name, True);
+ if (gtk_workarea_prop != None) {
+ unsigned long workarea_len = 0;
+ unsigned char *workarea_data = nullptr;
+ if (XGetWindowProperty(x11_display, x11_window, gtk_workarea_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &workarea_len, &remaining, &workarea_data) == Success) {
+ if ((format == 32) && (workarea_len % 4 == 0) && workarea_data) {
+ long *rect_data = (long *)workarea_data;
+ for (uint32_t data_offset = 0; data_offset < workarea_len; data_offset += 4) {
+ Rect2i workarea_rect;
+ workarea_rect.position.x = rect_data[data_offset];
+ workarea_rect.position.y = rect_data[data_offset + 1];
+ workarea_rect.size.x = rect_data[data_offset + 2];
+ workarea_rect.size.y = rect_data[data_offset + 3];
+
+ // Intersect with actual monitor size to find the correct area,
+ // because areas are not in the same order as screens from Xinerama.
+ if (rect.grow(-1).intersects(workarea_rect)) {
+ rect = rect.intersection(workarea_rect);
+ XFree(workarea_data);
+ return rect;
+ }
+ }
+ }
+ }
+ if (workarea_data) {
+ XFree(workarea_data);
+ }
+ }
+ }
- // Check if screen is valid
- ERR_FAIL_INDEX_V(p_screen, count, Rect2i(0, 0, 0, 0));
+ // Fallback to calculating work area by hand from struts.
+ Atom client_list_prop = XInternAtom(x11_display, "_NET_CLIENT_LIST", True);
+ if (client_list_prop != None) {
+ unsigned long clients_len = 0;
+ unsigned char *clients_data = nullptr;
+ if (XGetWindowProperty(x11_display, x11_window, client_list_prop, 0, LONG_MAX, False, XA_WINDOW, &type, &format, &clients_len, &remaining, &clients_data) == Success) {
+ if ((format == 32) && (clients_len > 0) && clients_data) {
+ Window *windows_data = (Window *)clients_data;
+
+ Rect2i desktop_rect;
+ bool desktop_valid = false;
+
+ // Get full desktop size.
+ {
+ Atom desktop_geometry_prop = XInternAtom(x11_display, "_NET_DESKTOP_GEOMETRY", True);
+ if (desktop_geometry_prop != None) {
+ unsigned long geom_len = 0;
+ unsigned char *geom_data = nullptr;
+ if (XGetWindowProperty(x11_display, x11_window, desktop_geometry_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &geom_len, &remaining, &geom_data) == Success) {
+ if ((format == 32) && (geom_len >= 2) && geom_data) {
+ desktop_valid = true;
+ long *size_data = (long *)geom_data;
+ desktop_rect.size.x = size_data[0];
+ desktop_rect.size.y = size_data[1];
+ }
+ }
+ if (geom_data) {
+ XFree(geom_data);
+ }
+ }
+ }
+
+ // Get full desktop position.
+ if (desktop_valid) {
+ Atom desktop_viewport_prop = XInternAtom(x11_display, "_NET_DESKTOP_VIEWPORT", True);
+ if (desktop_viewport_prop != None) {
+ unsigned long viewport_len = 0;
+ unsigned char *viewport_data = nullptr;
+ if (XGetWindowProperty(x11_display, x11_window, desktop_viewport_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &viewport_len, &remaining, &viewport_data) == Success) {
+ if ((format == 32) && (viewport_len >= 2) && viewport_data) {
+ desktop_valid = true;
+ long *pos_data = (long *)viewport_data;
+ desktop_rect.position.x = pos_data[0];
+ desktop_rect.position.y = pos_data[1];
+ }
+ }
+ if (viewport_data) {
+ XFree(viewport_data);
+ }
+ }
+ }
+
+ if (desktop_valid) {
+ use_simple_method = false;
+
+ for (unsigned long win_index = 0; win_index < clients_len; ++win_index) {
+ // Remove strut size from desktop size to get a more accurate result.
+ bool strut_found = false;
+ unsigned long strut_len = 0;
+ unsigned char *strut_data = nullptr;
+ Atom strut_partial_prop = XInternAtom(x11_display, "_NET_WM_STRUT_PARTIAL", True);
+ if (strut_partial_prop != None) {
+ if (XGetWindowProperty(x11_display, windows_data[win_index], strut_partial_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &strut_len, &remaining, &strut_data) == Success) {
+ strut_found = true;
+ }
+ }
+ // Fallback to older strut property.
+ if (!strut_found) {
+ Atom strut_prop = XInternAtom(x11_display, "_NET_WM_STRUT", True);
+ if (strut_prop != None) {
+ if (XGetWindowProperty(x11_display, windows_data[win_index], strut_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &strut_len, &remaining, &strut_data) == Success) {
+ strut_found = true;
+ }
+ }
+ }
+ if (strut_found && (format == 32) && (strut_len >= 4) && strut_data) {
+ long *struts = (long *)strut_data;
+
+ long left = struts[0];
+ long right = struts[1];
+ long top = struts[2];
+ long bottom = struts[3];
+
+ long left_start_y, left_end_y, right_start_y, right_end_y;
+ long top_start_x, top_end_x, bottom_start_x, bottom_end_x;
+
+ if (strut_len >= 12) {
+ left_start_y = struts[4];
+ left_end_y = struts[5];
+ right_start_y = struts[6];
+ right_end_y = struts[7];
+ top_start_x = struts[8];
+ top_end_x = struts[9];
+ bottom_start_x = struts[10];
+ bottom_end_x = struts[11];
+ } else {
+ left_start_y = 0;
+ left_end_y = desktop_rect.size.y;
+ right_start_y = 0;
+ right_end_y = desktop_rect.size.y;
+ top_start_x = 0;
+ top_end_x = desktop_rect.size.x;
+ bottom_start_x = 0;
+ bottom_end_x = desktop_rect.size.x;
+ }
+
+ const Point2i &pos = desktop_rect.position;
+ const Size2i &size = desktop_rect.size;
+
+ Rect2i left_rect(pos.x, pos.y + left_start_y, left, left_end_y - left_start_y);
+ if (left_rect.size.x > 0) {
+ Rect2i intersection = rect.intersection(left_rect);
+ if (!intersection.has_no_area() && intersection.size.x < rect.size.x) {
+ rect.position.x = left_rect.size.x;
+ rect.size.x = rect.size.x - intersection.size.x;
+ }
+ }
+
+ Rect2i right_rect(pos.x + size.x - right, pos.y + right_start_y, right, right_end_y - right_start_y);
+ if (right_rect.size.x > 0) {
+ Rect2i intersection = rect.intersection(right_rect);
+ if (!intersection.has_no_area() && right_rect.size.x < rect.size.x) {
+ rect.size.x = intersection.position.x - rect.position.x;
+ }
+ }
+
+ Rect2i top_rect(pos.x + top_start_x, pos.y, top_end_x - top_start_x, top);
+ if (top_rect.size.y > 0) {
+ Rect2i intersection = rect.intersection(top_rect);
+ if (!intersection.has_no_area() && intersection.size.y < rect.size.y) {
+ rect.position.y = top_rect.size.y;
+ rect.size.y = rect.size.y - intersection.size.y;
+ }
+ }
+
+ Rect2i bottom_rect(pos.x + bottom_start_x, pos.y + size.y - bottom, bottom_end_x - bottom_start_x, bottom);
+ if (bottom_rect.size.y > 0) {
+ Rect2i intersection = rect.intersection(bottom_rect);
+ if (!intersection.has_no_area() && right_rect.size.y < rect.size.y) {
+ rect.size.y = intersection.position.y - rect.position.y;
+ }
+ }
+ }
+ if (strut_data) {
+ XFree(strut_data);
+ }
+ }
+ }
+ }
+ }
+ if (clients_data) {
+ XFree(clients_data);
+ }
+ }
+ }
+
+ // Single screen or fallback for multi screen.
+ if (use_simple_method) {
+ // Get desktop available size from the global work area.
+ Atom workarea_prop = XInternAtom(x11_display, "_NET_WORKAREA", True);
+ if (workarea_prop != None) {
+ unsigned long workarea_len = 0;
+ unsigned char *workarea_data = nullptr;
+ if (XGetWindowProperty(x11_display, x11_window, workarea_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &workarea_len, &remaining, &workarea_data) == Success) {
+ if ((format == 32) && (workarea_len >= ((desktop_index + 1) * 4)) && workarea_data) {
+ long *rect_data = (long *)workarea_data;
+ int data_offset = desktop_index * 4;
+ Rect2i workarea_rect;
+ workarea_rect.position.x = rect_data[data_offset];
+ workarea_rect.position.y = rect_data[data_offset + 1];
+ workarea_rect.size.x = rect_data[data_offset + 2];
+ workarea_rect.size.y = rect_data[data_offset + 3];
+
+ // Intersect with actual monitor size to get a proper approximation in multi-screen setup.
+ if (!is_multiscreen) {
+ rect = workarea_rect;
+ } else if (rect.intersects(workarea_rect)) {
+ rect = rect.intersection(workarea_rect);
+ }
+ }
+ }
+ if (workarea_data) {
+ XFree(workarea_data);
+ }
+ }
+ }
- Rect2i rect = Rect2i(xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height);
- XFree(xsi);
return rect;
}
@@ -870,6 +1135,12 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
context_vulkan->window_destroy(p_id);
}
#endif
+#ifdef GLES3_ENABLED
+ if (gl_manager) {
+ gl_manager->window_destroy(p_id);
+ }
+#endif
+
XUnmapWindow(x11_display, wd.x11_window);
XDestroyWindow(x11_display, wd.x11_window);
if (wd.xic) {
@@ -1011,22 +1282,38 @@ void DisplayServerX11::window_set_drop_files_callback(const Callable &p_callable
int DisplayServerX11::window_get_current_screen(WindowID p_window) const {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(!windows.has(p_window), -1);
+ int count = get_screen_count();
+ if (count < 2) {
+ // Early exit with single monitor.
+ return 0;
+ }
+
+ ERR_FAIL_COND_V(!windows.has(p_window), 0);
const WindowData &wd = windows[p_window];
- int x, y;
- Window child;
- XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
+ const Rect2i window_rect(wd.position, wd.size);
- int count = get_screen_count();
+ // Find which monitor has the largest overlap with the given window.
+ int screen_index = 0;
+ int max_area = 0;
for (int i = 0; i < count; i++) {
- Point2i pos = screen_get_position(i);
- Size2i size = screen_get_size(i);
- if ((x >= pos.x && x < pos.x + size.width) && (y >= pos.y && y < pos.y + size.height)) {
- return i;
+ Rect2i screen_rect = _screen_get_rect(i);
+ Rect2i intersection = screen_rect.intersection(window_rect);
+ int area = intersection.get_area();
+ if (area > max_area) {
+ max_area = area;
+ screen_index = i;
}
}
- return 0;
+
+ return screen_index;
+}
+
+void DisplayServerX11::gl_window_make_current(DisplayServer::WindowID p_window_id) {
+#if defined(GLES3_ENABLED)
+ if (gl_manager)
+ gl_manager->window_make_current(p_window_id);
+#endif
}
void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window) {
@@ -2485,11 +2772,11 @@ Atom DisplayServerX11::_process_selection_request_target(Atom p_target, Window p
0);
return p_property;
} else if (p_target == XInternAtom(x11_display, "UTF8_STRING", 0) ||
- p_target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
- p_target == XInternAtom(x11_display, "TEXT", 0) ||
- p_target == XA_STRING ||
- p_target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) ||
- p_target == XInternAtom(x11_display, "text/plain", 0)) {
+ p_target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
+ p_target == XInternAtom(x11_display, "TEXT", 0) ||
+ p_target == XA_STRING ||
+ p_target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) ||
+ p_target == XInternAtom(x11_display, "text/plain", 0)) {
// Directly using internal clipboard because we know our window
// is the owner during a selection request.
CharString clip;
@@ -2625,6 +2912,11 @@ void DisplayServerX11::_window_changed(XEvent *event) {
context_vulkan->window_resize(window_id, wd.size.width, wd.size.height);
}
#endif
+#if defined(GLES3_ENABLED)
+ if (gl_manager) {
+ gl_manager->window_resize(window_id, wd.size.width, wd.size.height);
+ }
+#endif
if (!wd.rect_changed_callback.is_null()) {
Rect2i r = new_rect;
@@ -2725,27 +3017,34 @@ void DisplayServerX11::_poll_events() {
{
MutexLock mutex_lock(events_mutex);
- // Non-blocking wait for next event and remove it from the queue.
- XEvent ev;
- while (XCheckIfEvent(x11_display, &ev, _predicate_all_events, nullptr)) {
- // Check if the input manager wants to process the event.
- if (XFilterEvent(&ev, None)) {
- // Event has been filtered by the Input Manager,
- // it has to be ignored and a new one will be received.
- continue;
- }
+ _check_pending_events(polled_events);
+ }
+ }
+}
- // Handle selection request events directly in the event thread, because
- // communication through the x server takes several events sent back and forth
- // and we don't want to block other programs while processing only one each frame.
- if (ev.type == SelectionRequest) {
- _handle_selection_request_event(&(ev.xselectionrequest));
- continue;
- }
+void DisplayServerX11::_check_pending_events(LocalVector<XEvent> &r_events) {
+ // Flush to make sure to gather all pending events.
+ XFlush(x11_display);
- polled_events.push_back(ev);
- }
+ // Non-blocking wait for next event and remove it from the queue.
+ XEvent ev;
+ while (XCheckIfEvent(x11_display, &ev, _predicate_all_events, nullptr)) {
+ // Check if the input manager wants to process the event.
+ if (XFilterEvent(&ev, None)) {
+ // Event has been filtered by the Input Manager,
+ // it has to be ignored and a new one will be received.
+ continue;
+ }
+
+ // Handle selection request events directly in the event thread, because
+ // communication through the x server takes several events sent back and forth
+ // and we don't want to block other programs while processing only one each frame.
+ if (ev.type == SelectionRequest) {
+ _handle_selection_request_event(&(ev.xselectionrequest));
+ continue;
}
+
+ r_events.push_back(ev);
}
}
@@ -2798,6 +3097,9 @@ void DisplayServerX11::process_events() {
MutexLock mutex_lock(events_mutex);
events = polled_events;
polled_events.clear();
+
+ // Check for more pending events to avoid an extra frame delay.
+ _check_pending_events(events);
}
for (uint32_t event_index = 0; event_index < events.size(); ++event_index) {
@@ -2857,7 +3159,7 @@ void DisplayServerX11::process_events() {
if (pen_pressure_range != Vector2()) {
xi.pressure_supported = true;
xi.pressure = (*values - pen_pressure_range[0]) /
- (pen_pressure_range[1] - pen_pressure_range[0]);
+ (pen_pressure_range[1] - pen_pressure_range[0]);
}
}
@@ -2916,10 +3218,7 @@ void DisplayServerX11::process_events() {
xi.last_relative_time = raw_event->time;
} break;
#ifdef TOUCH_ENABLED
- case XI_TouchBegin: // Fall-through
- // Disabled hand-in-hand with the grabbing
- //XIAllowTouchEvents(x11_display, event_data->deviceid, event_data->detail, x11_window, XIAcceptTouch);
-
+ case XI_TouchBegin:
case XI_TouchEnd: {
bool is_begin = event_data->evtype == XI_TouchBegin;
@@ -3494,12 +3793,23 @@ void DisplayServerX11::process_events() {
}
void DisplayServerX11::release_rendering_thread() {
+#if defined(GLES3_ENABLED)
+// gl_manager->release_current();
+#endif
}
void DisplayServerX11::make_rendering_thread() {
+#if defined(GLES3_ENABLED)
+// gl_manager->make_current();
+#endif
}
void DisplayServerX11::swap_buffers() {
+#if defined(GLES3_ENABLED)
+ if (gl_manager) {
+ gl_manager->swap_buffers();
+ }
+#endif
}
void DisplayServerX11::_update_context(WindowData &wd) {
@@ -3641,17 +3951,31 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
_THREAD_SAFE_METHOD_
#if defined(VULKAN_ENABLED)
- context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+ if (context_vulkan) {
+ context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+ }
+#endif
+
+#if defined(GLES3_ENABLED)
+ if (gl_manager) {
+ gl_manager->set_use_vsync(p_vsync_mode == DisplayServer::VSYNC_ENABLED);
+ }
#endif
}
DisplayServer::VSyncMode DisplayServerX11::window_get_vsync_mode(WindowID p_window) const {
_THREAD_SAFE_METHOD_
#if defined(VULKAN_ENABLED)
- return context_vulkan->get_vsync_mode(p_window);
-#else
- return DisplayServer::VSYNC_ENABLED;
+ if (context_vulkan) {
+ return context_vulkan->get_vsync_mode(p_window);
+ }
+#endif
+#if defined(GLES3_ENABLED)
+ if (gl_manager) {
+ return gl_manager->is_using_vsync() ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED;
+ }
#endif
+ return DisplayServer::VSYNC_ENABLED;
}
Vector<String> DisplayServerX11::get_rendering_drivers_func() {
@@ -3660,8 +3984,8 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
#ifdef VULKAN_ENABLED
drivers.push_back("vulkan");
#endif
-#ifdef OPENGL_ENABLED
- drivers.push_back("opengl");
+#ifdef GLES3_ENABLED
+ drivers.push_back("opengl3");
#endif
return drivers;
@@ -3670,7 +3994,7 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.\n"
+ OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.\n"
"Please update your drivers or if you have a very old or integrated GPU, upgrade it.\n"
"If you have updated your graphics drivers recently, try rebooting.",
"Unable to initialize Video driver");
@@ -3746,18 +4070,18 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
XSetWindowAttributes new_attr;
new_attr.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask |
- ButtonReleaseMask | EnterWindowMask |
- LeaveWindowMask | PointerMotionMask |
- Button1MotionMask |
- Button2MotionMask | Button3MotionMask |
- Button4MotionMask | Button5MotionMask |
- ButtonMotionMask | KeymapStateMask |
- ExposureMask | VisibilityChangeMask |
- StructureNotifyMask |
- SubstructureNotifyMask | SubstructureRedirectMask |
- FocusChangeMask | PropertyChangeMask |
- ColormapChangeMask | OwnerGrabButtonMask |
- im_event_mask;
+ ButtonReleaseMask | EnterWindowMask |
+ LeaveWindowMask | PointerMotionMask |
+ Button1MotionMask |
+ Button2MotionMask | Button3MotionMask |
+ Button4MotionMask | Button5MotionMask |
+ ButtonMotionMask | KeymapStateMask |
+ ExposureMask | VisibilityChangeMask |
+ StructureNotifyMask |
+ SubstructureNotifyMask | SubstructureRedirectMask |
+ FocusChangeMask | PropertyChangeMask |
+ ColormapChangeMask | OwnerGrabButtonMask |
+ im_event_mask;
XChangeWindowAttributes(x11_display, wd.x11_window, CWEventMask, &new_attr);
@@ -3846,6 +4170,12 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan window");
}
#endif
+#ifdef GLES3_ENABLED
+ if (gl_manager) {
+ Error err = gl_manager->window_create(id, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height);
+ ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL window");
+ }
+#endif
//set_class_hint(x11_display, wd.x11_window);
XFlush(x11_display);
@@ -4027,14 +4357,10 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
xdnd_selection = XInternAtom(x11_display, "XdndSelection", False);
//!!!!!!!!!!!!!!!!!!!!!!!!!!
- //TODO - do Vulkan and GLES2 support checks, driver selection and fallback
+ //TODO - do Vulkan and OpenGL support checks, driver selection and fallback
rendering_driver = p_rendering_driver;
-#ifndef _MSC_VER
-#warning Forcing vulkan rendering driver because OpenGL not implemented yet
-#endif
- rendering_driver = "vulkan";
-
+ bool driver_found = false;
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
context_vulkan = memnew(VulkanContextX11);
@@ -4044,11 +4370,12 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
r_error = ERR_CANT_CREATE;
ERR_FAIL_MSG("Could not initialize Vulkan");
}
+ driver_found = true;
}
#endif
- // Init context and rendering device
-#if defined(OPENGL_ENABLED)
- if (rendering_driver == "opengl_es") {
+ // Initialize context and rendering device.
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
if (getenv("DRI_PRIME") == nullptr) {
int use_prime = -1;
@@ -4090,28 +4417,37 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
}
- ContextGL_X11::ContextType opengl_api_type = ContextGL_X11::GLES_2_0_COMPATIBLE;
+ GLManager_X11::ContextType opengl_api_type = GLManager_X11::GLES_3_0_COMPATIBLE;
- context_gles2 = memnew(ContextGL_X11(x11_display, x11_window, current_videomode, opengl_api_type));
+ gl_manager = memnew(GLManager_X11(p_resolution, opengl_api_type));
- if (context_gles2->initialize() != OK) {
- memdelete(context_gles2);
- context_gles2 = nullptr;
- ERR_FAIL_V(ERR_UNAVAILABLE);
+ if (gl_manager->initialize() != OK) {
+ memdelete(gl_manager);
+ gl_manager = nullptr;
+ r_error = ERR_UNAVAILABLE;
+ return;
}
+ driver_found = true;
- context_gles2->set_use_vsync(current_videomode.use_vsync);
+ // gl_manager->set_use_vsync(current_videomode.use_vsync);
- if (RasterizerGLES2::is_viable() == OK) {
- RasterizerGLES2::register_config();
- RasterizerGLES2::make_current();
+ if (true) {
+ // if (RasterizerGLES3::is_viable() == OK) {
+ // RasterizerGLES3::register_config();
+ RasterizerGLES3::make_current();
} else {
- memdelete(context_gles2);
- context_gles2 = nullptr;
- ERR_FAIL_V(ERR_UNAVAILABLE);
+ memdelete(gl_manager);
+ gl_manager = nullptr;
+ r_error = ERR_UNAVAILABLE;
+ return;
}
}
#endif
+ if (!driver_found) {
+ r_error = ERR_UNAVAILABLE;
+ ERR_FAIL_MSG("Video driver not found");
+ }
+
Point2i window_position(
(screen_get_size(0).width - p_resolution.width) / 2,
(screen_get_size(0).height - p_resolution.height) / 2);
@@ -4127,7 +4463,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
show_window(main_window);
-//create RenderingDevice if used
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
//temporary
@@ -4138,13 +4473,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
#endif
- /*
- rendering_server = memnew(RenderingServerDefault);
- if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
- rendering_server = memnew(RenderingServerWrapMT(rendering_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
- }
- */
-
{
//set all event master mask
XIEventMask all_master_event_mask;
@@ -4157,15 +4485,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
XISelectEvents(x11_display, DefaultRootWindow(x11_display), &all_master_event_mask, 1);
}
- // Disabled by now since grabbing also blocks mouse events
- // (they are received as extended events instead of standard events)
- /*XIClearMask(xi.touch_event_mask.mask, XI_TouchOwnership);
-
- // Grab touch devices to avoid OS gesture interference
- for (int i = 0; i < xi.touch_devices.size(); ++i) {
- XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
- }*/
-
cursor_size = XcursorGetDefaultSize(x11_display);
cursor_theme = XcursorGetTheme(x11_display);
@@ -4331,6 +4650,11 @@ DisplayServerX11::~DisplayServerX11() {
context_vulkan->window_destroy(E.key);
}
#endif
+#ifdef GLES3_ENABLED
+ if (rendering_driver == "opengl3") {
+ gl_manager->window_destroy(E.key);
+ }
+#endif
WindowData &wd = E.value;
if (wd.xic) {
@@ -4355,6 +4679,13 @@ DisplayServerX11::~DisplayServerX11() {
}
#endif
+#ifdef GLES3_ENABLED
+ if (gl_manager) {
+ memdelete(gl_manager);
+ gl_manager = nullptr;
+ }
+#endif
+
if (xrandr_handle) {
dlclose(xrandr_handle);
}