You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-25 15:37:42 +00:00
Wayland: Implement game embedding
This patch introduces a new protocol proxy, which multiplxes Wayland clients into a single connection, allowing us to redirect calls (e.g. create toplevel -> create subsurface). Mixed with some state tracking and emulation, we can embed a full-featured client into the editor.
This commit is contained in:
@@ -643,6 +643,12 @@ Copyright: 2008-2013, Kristian Høgsberg
|
||||
2015, Red Hat Inc.
|
||||
License: Expat
|
||||
|
||||
Files: thirdparty/wayland-protocols/mesa/wayland-drm.xml
|
||||
Comment: Mesa Wayland protocols
|
||||
Copyright: 2008-2011, Kristian Høgsberg
|
||||
2010-2011, Intel Corporation
|
||||
License: X11
|
||||
|
||||
Files: thirdparty/wslay/*
|
||||
Comment: Wslay
|
||||
Copyright: 2011, 2012, 2015, Tatsuhiro Tsujikawa
|
||||
@@ -2305,6 +2311,28 @@ License: WOL
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
|
||||
ANY KIND. See https://dspguru.com/wide-open-license/ for more information.
|
||||
|
||||
License: X11
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that\n the above copyright notice appear in
|
||||
all copies and that both that copyright notice and this permission
|
||||
notice appear in supporting documentation, and that the name of
|
||||
the copyright holders not be used in advertising or publicity
|
||||
pertaining to distribution of the software without specific,
|
||||
written prior permission. The copyright holders make no
|
||||
representations about the suitability of this software for any
|
||||
purpose. It is provided "as is" without express or implied
|
||||
warranty.
|
||||
.
|
||||
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
|
||||
License: Zlib
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -668,7 +668,7 @@ GameView::EmbedAvailability GameView::_get_embed_available() {
|
||||
return EMBED_NOT_AVAILABLE_SINGLE_WINDOW_MODE;
|
||||
}
|
||||
String display_driver = GLOBAL_GET("display/display_server/driver");
|
||||
if (display_driver == "headless" || display_driver == "wayland") {
|
||||
if (display_driver == "headless") {
|
||||
return EMBED_NOT_AVAILABLE_PROJECT_DISPLAY_DRIVER;
|
||||
}
|
||||
|
||||
@@ -714,11 +714,7 @@ void GameView::_update_ui() {
|
||||
}
|
||||
break;
|
||||
case EMBED_NOT_AVAILABLE_FEATURE_NOT_SUPPORTED:
|
||||
if (DisplayServer::get_singleton()->get_name() == "Wayland") {
|
||||
state_label->set_text(TTRC("Game embedding not available on Wayland.\nWayland can be disabled in the Editor Settings (Run > Platforms > Linux/*BSD > Prefer Wayland)."));
|
||||
} else {
|
||||
state_label->set_text(TTRC("Game embedding not available on your OS."));
|
||||
}
|
||||
break;
|
||||
case EMBED_NOT_AVAILABLE_PROJECT_DISPLAY_DRIVER:
|
||||
state_label->set_text(vformat(TTR("Game embedding not available for the Display Server: '%s'.\nDisplay Server can be modified in the Project Settings (Display > Display Server > Driver)."), GLOBAL_GET("display/display_server/driver")));
|
||||
@@ -991,6 +987,21 @@ void GameView::_update_arguments_for_instance(int p_idx, List<String> &r_argumen
|
||||
// macOS requires the embedded display driver.
|
||||
remove_args.insert("--display-driver");
|
||||
#endif
|
||||
|
||||
#ifdef WAYLAND_ENABLED
|
||||
// Wayland requires its display driver.
|
||||
if (DisplayServer::get_singleton()->get_name() == "Wayland") {
|
||||
remove_args.insert("--display-driver");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef X11_ENABLED
|
||||
// X11 requires its display driver.
|
||||
if (DisplayServer::get_singleton()->get_name() == "X11") {
|
||||
remove_args.insert("--display-driver");
|
||||
}
|
||||
#endif
|
||||
|
||||
while (E) {
|
||||
List<String>::Element *N = E->next();
|
||||
|
||||
@@ -1020,6 +1031,20 @@ void GameView::_update_arguments_for_instance(int p_idx, List<String> &r_argumen
|
||||
N = r_arguments.insert_after(N, "--embedded");
|
||||
#endif
|
||||
|
||||
#ifdef WAYLAND_ENABLED
|
||||
if (DisplayServer::get_singleton()->get_name() == "Wayland") {
|
||||
N = r_arguments.insert_after(N, "--display-driver");
|
||||
N = r_arguments.insert_after(N, "wayland");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef X11_ENABLED
|
||||
if (DisplayServer::get_singleton()->get_name() == "X11") {
|
||||
N = r_arguments.insert_after(N, "--display-driver");
|
||||
N = r_arguments.insert_after(N, "x11");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Be sure to have the correct window size in the embedded_process control.
|
||||
_update_embed_window_size();
|
||||
Rect2i rect = embedded_process->get_screen_embedded_window_rect();
|
||||
|
||||
@@ -97,6 +97,21 @@ generated_sources = [
|
||||
generate_from_xml(
|
||||
"xdg_foreign_v2", "#thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v2.xml"
|
||||
),
|
||||
generate_from_xml("linux_dmabuf_v1", "#thirdparty/wayland-protocols/stable/linux-dmabuf/linux-dmabuf-v1.xml"),
|
||||
generate_from_xml(
|
||||
"linux_explicit_synchronization_unstable_v1",
|
||||
"#thirdparty/wayland-protocols/unstable/linux-explicit-synchronization/linux-explicit-synchronization-unstable-v1.xml",
|
||||
),
|
||||
generate_from_xml("fifo_v1", "#thirdparty/wayland-protocols/staging/fifo/fifo-v1.xml"),
|
||||
generate_from_xml("commit_timing_v1", "#thirdparty/wayland-protocols/staging/commit-timing/commit-timing-v1.xml"),
|
||||
generate_from_xml(
|
||||
"linux_drm_syncobj_v1", "#thirdparty/wayland-protocols/staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml"
|
||||
),
|
||||
generate_from_xml(
|
||||
"tearing_control_v1", "#thirdparty/wayland-protocols/staging/tearing-control/tearing-control-v1.xml"
|
||||
),
|
||||
generate_from_xml("wayland-drm", "#thirdparty/wayland-protocols/mesa/wayland-drm.xml"),
|
||||
generate_from_xml("godot_embedding_compositor", "godot-embedding-compositor.xml"),
|
||||
]
|
||||
|
||||
source_files = generated_sources + [
|
||||
@@ -104,6 +119,7 @@ source_files = generated_sources + [
|
||||
File("display_server_wayland.cpp"),
|
||||
File("key_mapping_xkb.cpp"),
|
||||
File("wayland_thread.cpp"),
|
||||
File("wayland_embedder.cpp"),
|
||||
]
|
||||
|
||||
if env["use_sowrap"]:
|
||||
|
||||
@@ -195,6 +195,7 @@ bool DisplayServerWayland::has_feature(Feature p_feature) const {
|
||||
case FEATURE_WINDOW_DRAG:
|
||||
case FEATURE_CLIPBOARD_PRIMARY:
|
||||
case FEATURE_SUBWINDOWS:
|
||||
case FEATURE_WINDOW_EMBEDDING:
|
||||
case FEATURE_SELF_FITTING_WINDOWS: {
|
||||
return true;
|
||||
} break;
|
||||
@@ -1298,6 +1299,8 @@ void DisplayServerWayland::window_move_to_foreground(DisplayServer::WindowID p_w
|
||||
}
|
||||
|
||||
bool DisplayServerWayland::window_is_focused(WindowID p_window_id) const {
|
||||
MutexLock mutex_lock(wayland_thread.mutex);
|
||||
|
||||
return wayland_thread.pointer_get_pointed_window_id() == p_window_id;
|
||||
}
|
||||
|
||||
@@ -1505,6 +1508,94 @@ bool DisplayServerWayland::get_swap_cancel_ok() {
|
||||
return swap_cancel_ok;
|
||||
}
|
||||
|
||||
Error DisplayServerWayland::embed_process(WindowID p_window, OS::ProcessID p_pid, const Rect2i &p_rect, bool p_visible, bool p_grab_focus) {
|
||||
MutexLock mutex_lock(wayland_thread.mutex);
|
||||
|
||||
struct godot_embedding_compositor *ec = wayland_thread.get_embedding_compositor();
|
||||
ERR_FAIL_NULL_V_MSG(ec, ERR_BUG, "Missing embedded compositor interface");
|
||||
|
||||
struct WaylandThread::EmbeddingCompositorState *ecs = WaylandThread::godot_embedding_compositor_get_state(ec);
|
||||
ERR_FAIL_NULL_V(ecs, ERR_BUG);
|
||||
|
||||
if (!ecs->mapped_clients.has(p_pid)) {
|
||||
return ERR_DOES_NOT_EXIST;
|
||||
}
|
||||
|
||||
struct godot_embedded_client *embedded_client = ecs->mapped_clients[p_pid];
|
||||
WaylandThread::EmbeddedClientState *client_data = (WaylandThread::EmbeddedClientState *)godot_embedded_client_get_user_data(embedded_client);
|
||||
ERR_FAIL_NULL_V(client_data, ERR_BUG);
|
||||
|
||||
if (p_grab_focus) {
|
||||
godot_embedded_client_focus_window(embedded_client);
|
||||
}
|
||||
|
||||
if (p_visible) {
|
||||
WaylandThread::WindowState *ws = wayland_thread.window_get_state(p_window);
|
||||
ERR_FAIL_NULL_V(ws, ERR_BUG);
|
||||
|
||||
struct xdg_toplevel *toplevel = ws->xdg_toplevel;
|
||||
|
||||
if (toplevel == nullptr && ws->libdecor_frame) {
|
||||
toplevel = libdecor_frame_get_xdg_toplevel(ws->libdecor_frame);
|
||||
}
|
||||
|
||||
ERR_FAIL_NULL_V(toplevel, ERR_CANT_CREATE);
|
||||
|
||||
godot_embedded_client_set_embedded_window_parent(embedded_client, toplevel);
|
||||
|
||||
double window_scale = WaylandThread::window_state_get_scale_factor(ws);
|
||||
|
||||
Rect2i scaled_rect = p_rect;
|
||||
scaled_rect.position = WaylandThread::scale_vector2i(scaled_rect.position, 1 / window_scale);
|
||||
scaled_rect.size = WaylandThread::scale_vector2i(scaled_rect.size, 1 / window_scale);
|
||||
|
||||
print_verbose(vformat("Scaling embedded rect down by %f from %s to %s.", window_scale, p_rect, scaled_rect));
|
||||
|
||||
godot_embedded_client_set_embedded_window_rect(embedded_client, scaled_rect.position.x, scaled_rect.position.y, scaled_rect.size.width, scaled_rect.size.height);
|
||||
} else {
|
||||
godot_embedded_client_set_embedded_window_parent(embedded_client, nullptr);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error DisplayServerWayland::request_close_embedded_process(OS::ProcessID p_pid) {
|
||||
MutexLock mutex_lock(wayland_thread.mutex);
|
||||
|
||||
struct godot_embedding_compositor *ec = wayland_thread.get_embedding_compositor();
|
||||
ERR_FAIL_NULL_V_MSG(ec, ERR_BUG, "Missing embedded compositor interface");
|
||||
|
||||
struct WaylandThread::EmbeddingCompositorState *ecs = WaylandThread::godot_embedding_compositor_get_state(ec);
|
||||
ERR_FAIL_NULL_V(ecs, ERR_BUG);
|
||||
|
||||
if (!ecs->mapped_clients.has(p_pid)) {
|
||||
return ERR_DOES_NOT_EXIST;
|
||||
}
|
||||
|
||||
struct godot_embedded_client *embedded_client = ecs->mapped_clients[p_pid];
|
||||
WaylandThread::EmbeddedClientState *client_data = (WaylandThread::EmbeddedClientState *)godot_embedded_client_get_user_data(embedded_client);
|
||||
ERR_FAIL_NULL_V(client_data, ERR_BUG);
|
||||
|
||||
godot_embedded_client_embedded_window_request_close(embedded_client);
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error DisplayServerWayland::remove_embedded_process(OS::ProcessID p_pid) {
|
||||
return request_close_embedded_process(p_pid);
|
||||
}
|
||||
|
||||
OS::ProcessID DisplayServerWayland::get_focused_process_id() {
|
||||
MutexLock mutex_lock(wayland_thread.mutex);
|
||||
|
||||
OS::ProcessID embedded_pid = wayland_thread.embedded_compositor_get_focused_pid();
|
||||
|
||||
if (embedded_pid < 0) {
|
||||
return OS::get_singleton()->get_process_id();
|
||||
}
|
||||
|
||||
return embedded_pid;
|
||||
}
|
||||
|
||||
int DisplayServerWayland::keyboard_get_layout_count() const {
|
||||
MutexLock mutex_lock(wayland_thread.mutex);
|
||||
|
||||
|
||||
@@ -328,6 +328,11 @@ public:
|
||||
|
||||
virtual bool get_swap_cancel_ok() override;
|
||||
|
||||
virtual Error embed_process(WindowID p_window, OS::ProcessID p_pid, const Rect2i &p_rect, bool p_visible, bool p_grab_focus) override;
|
||||
virtual Error request_close_embedded_process(OS::ProcessID p_pid) override;
|
||||
virtual Error remove_embedded_process(OS::ProcessID p_pid) override;
|
||||
virtual OS::ProcessID get_focused_process_id() override;
|
||||
|
||||
virtual int keyboard_get_layout_count() const override;
|
||||
virtual int keyboard_get_current_layout() const override;
|
||||
virtual void keyboard_set_current_layout(int p_index) override;
|
||||
|
||||
74
platform/linuxbsd/wayland/godot-embedding-compositor.xml
Normal file
74
platform/linuxbsd/wayland/godot-embedding-compositor.xml
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="godot_embedding_compositor">
|
||||
|
||||
<copyright>
|
||||
Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md).
|
||||
Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.
|
||||
|
||||
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.
|
||||
</copyright>
|
||||
|
||||
<interface name="godot_embedding_compositor" version="1">
|
||||
<description summary="Main control interface for embedding compositor"/>
|
||||
|
||||
<event name="client">
|
||||
<description summary="A new client connected to the compositor"/>
|
||||
<arg name="client" type="new_id" interface="godot_embedded_client"/>
|
||||
<arg name="pid" type="int"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="godot_embedded_client" version="1">
|
||||
<description summary="A client connected to the embedded compositor.">
|
||||
Clients have only a single embedded window at a time, subject to change.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor"/>
|
||||
|
||||
<request name="set_embedded_window_rect">
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
</request>
|
||||
|
||||
<request name="set_embedded_window_parent">
|
||||
<description summary="(Re)map onto an xdg_toplevel"/>
|
||||
<arg name="parent" type="object" interface="xdg_toplevel" allow-null="true"/>
|
||||
</request>
|
||||
|
||||
<request name="focus_window"/>
|
||||
|
||||
<request name="embedded_window_request_close"/>
|
||||
|
||||
<event name="disconnected">
|
||||
<description summary="The client got disconnected from the compositor">
|
||||
This instance is no longer valid. The compositor shall ignore any
|
||||
further request except destroy and stop emitting events for this object.
|
||||
After this event, the client can safely destroy this object.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<event name="window_embedded"/>
|
||||
|
||||
<event name="window_focus_in"/>
|
||||
|
||||
<event name="window_focus_out"/>
|
||||
</interface>
|
||||
</protocol>
|
||||
2970
platform/linuxbsd/wayland/wayland_embedder.cpp
Normal file
2970
platform/linuxbsd/wayland/wayland_embedder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
630
platform/linuxbsd/wayland/wayland_embedder.h
Normal file
630
platform/linuxbsd/wayland/wayland_embedder.h
Normal file
@@ -0,0 +1,630 @@
|
||||
/**************************************************************************/
|
||||
/* wayland_embedder.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef WAYLAND_ENABLED
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "core/templates/a_hash_map.h"
|
||||
#include "core/templates/pooled_list.h"
|
||||
|
||||
#ifdef SOWRAP_ENABLED
|
||||
#include "wayland/dynwrappers/wayland-client-core-so_wrap.h"
|
||||
#else
|
||||
#include <wayland-client-core.h>
|
||||
#endif
|
||||
|
||||
#include "protocol/wayland.gen.h"
|
||||
|
||||
#include "protocol/linux_dmabuf_v1.gen.h"
|
||||
#include "protocol/xdg_shell.gen.h"
|
||||
|
||||
#include "protocol/commit_timing_v1.gen.h"
|
||||
#include "protocol/cursor_shape.gen.h"
|
||||
#include "protocol/fifo_v1.gen.h"
|
||||
#include "protocol/fractional_scale.gen.h"
|
||||
#include "protocol/godot_embedding_compositor.gen.h"
|
||||
#include "protocol/idle_inhibit.gen.h"
|
||||
#include "protocol/linux_drm_syncobj_v1.gen.h"
|
||||
#include "protocol/linux_explicit_synchronization_unstable_v1.gen.h"
|
||||
#include "protocol/pointer_constraints.gen.h"
|
||||
#include "protocol/pointer_gestures.gen.h"
|
||||
#include "protocol/primary_selection.gen.h"
|
||||
#include "protocol/relative_pointer.gen.h"
|
||||
#include "protocol/tablet.gen.h"
|
||||
#include "protocol/tearing_control_v1.gen.h"
|
||||
#include "protocol/text_input.gen.h"
|
||||
#include "protocol/viewporter.gen.h"
|
||||
#include "protocol/wayland-drm.gen.h"
|
||||
#include "protocol/xdg_activation.gen.h"
|
||||
#include "protocol/xdg_decoration.gen.h"
|
||||
#include "protocol/xdg_foreign_v1.gen.h"
|
||||
#include "protocol/xdg_foreign_v2.gen.h"
|
||||
#include "protocol/xdg_shell.gen.h"
|
||||
#include "protocol/xdg_system_bell.gen.h"
|
||||
#include "protocol/xdg_toplevel_icon.gen.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/os/thread.h"
|
||||
|
||||
// TODO: Consider resizing the ancillary buffer dynamically.
|
||||
#define EMBED_ANCILLARY_BUF_SIZE 4096
|
||||
|
||||
class WaylandEmbedder {
|
||||
enum class ProxyDirection {
|
||||
CLIENT,
|
||||
COMPOSITOR,
|
||||
};
|
||||
|
||||
enum class MessageStatus {
|
||||
HANDLED,
|
||||
UNHANDLED,
|
||||
INVALID,
|
||||
ERROR,
|
||||
};
|
||||
|
||||
struct msg_info {
|
||||
uint32_t raw_id = 0;
|
||||
uint16_t size = 0;
|
||||
uint16_t opcode = 0;
|
||||
|
||||
pid_t pid = 0;
|
||||
|
||||
ProxyDirection direction = ProxyDirection::CLIENT;
|
||||
|
||||
constexpr size_t words() const { return (size / sizeof(uint32_t)); }
|
||||
};
|
||||
|
||||
struct WaylandObjectData {
|
||||
virtual ~WaylandObjectData() = default;
|
||||
};
|
||||
|
||||
struct WaylandObject {
|
||||
const struct wl_interface *interface = nullptr;
|
||||
int version = 0;
|
||||
|
||||
// Inert, awaiting confirmation from server.
|
||||
bool destroyed = false;
|
||||
|
||||
// Other objects might depend on it and must not be destroyed.
|
||||
bool shared = false;
|
||||
|
||||
WaylandObjectData *data = nullptr;
|
||||
};
|
||||
|
||||
struct WaylandDrmGlobalData : WaylandObjectData {
|
||||
String device;
|
||||
LocalVector<uint32_t> formats;
|
||||
bool authenticated;
|
||||
uint32_t capabilities;
|
||||
};
|
||||
|
||||
struct WaylandShmGlobalData : WaylandObjectData {
|
||||
LocalVector<uint32_t> formats;
|
||||
};
|
||||
|
||||
struct Client {
|
||||
struct GlobalIdInfo {
|
||||
uint32_t id = INVALID_ID;
|
||||
List<uint32_t>::Element *history_elem = nullptr;
|
||||
|
||||
GlobalIdInfo() = default;
|
||||
GlobalIdInfo(uint32_t p_id, List<uint32_t>::Element *p_history_elem) :
|
||||
id(p_id), history_elem(p_history_elem) {}
|
||||
};
|
||||
|
||||
WaylandEmbedder *embedder = nullptr;
|
||||
|
||||
int socket = -1;
|
||||
|
||||
// NOTE: PIDs are not unique per client!
|
||||
pid_t pid = 0;
|
||||
|
||||
// FIXME: Names suck.
|
||||
AHashMap<uint32_t, HashSet<uint32_t>> registry_globals_instances;
|
||||
HashSet<uint32_t> wl_registry_instances;
|
||||
|
||||
List<uint32_t> global_id_history;
|
||||
AHashMap<uint32_t, GlobalIdInfo> global_ids;
|
||||
AHashMap<uint32_t, uint32_t> local_ids;
|
||||
|
||||
// Objects with no equivalent on the real compositor.
|
||||
AHashMap<uint32_t, WaylandObject> fake_objects;
|
||||
|
||||
// Objects which mirror events of a global object.
|
||||
AHashMap<uint32_t, WaylandObject> global_instances;
|
||||
|
||||
uint32_t embedded_client_id = INVALID_ID;
|
||||
uint32_t embedded_window_id = INVALID_ID;
|
||||
|
||||
List<int> fds;
|
||||
|
||||
// Clients obviously expect properly packed server IDs, so we need to allocate
|
||||
// them somehow. This approach mimics the one used in PooledList.
|
||||
uint32_t allocated_server_ids = INVALID_ID;
|
||||
LocalVector<uint32_t> free_server_ids;
|
||||
|
||||
uint32_t get_global_id(uint32_t p_local_id) const { return global_ids.has(p_local_id) ? global_ids[p_local_id].id : INVALID_ID; }
|
||||
uint32_t get_local_id(uint32_t p_global_id) const { return local_ids.has(p_global_id) ? local_ids[p_global_id] : INVALID_ID; }
|
||||
|
||||
uint32_t allocate_server_id();
|
||||
WaylandObject *get_object(uint32_t p_local_id);
|
||||
Error delete_object(uint32_t p_local_id);
|
||||
|
||||
Error bind_global_id(uint32_t p_global_id, uint32_t p_local_id);
|
||||
|
||||
uint32_t new_object(uint32_t p_local_id, const struct wl_interface *p_interface, int p_version = 1, WaylandObjectData *p_data = nullptr);
|
||||
uint32_t new_server_object(uint32_t p_global_id, const struct wl_interface *p_interface, int p_version = 1, WaylandObjectData *p_data = nullptr);
|
||||
WaylandObject *new_fake_object(uint32_t p_local_id, const struct wl_interface *p_interface, int p_version = 1, WaylandObjectData *p_data = nullptr);
|
||||
WaylandObject *new_global_instance(uint32_t p_local_id, uint32_t p_global_id, const struct wl_interface *p_interface, int p_version = 1, WaylandObjectData *p_data = nullptr);
|
||||
|
||||
Error send_wl_drm_state(uint32_t p_id, WaylandDrmGlobalData *p_state);
|
||||
};
|
||||
|
||||
// Local IDs are a mess to handle as they strictly depend on their client of
|
||||
// origin. This wrapper helps with that.
|
||||
class LocalObjectHandle {
|
||||
Client *client = nullptr;
|
||||
uint32_t local_id = INVALID_ID;
|
||||
|
||||
public:
|
||||
constexpr LocalObjectHandle() = default;
|
||||
|
||||
constexpr LocalObjectHandle(Client *p_client, uint32_t p_id) :
|
||||
client(p_client), local_id(p_id) {}
|
||||
|
||||
void invalidate() {
|
||||
client = nullptr;
|
||||
local_id = INVALID_ID;
|
||||
}
|
||||
constexpr bool is_valid() const { return client != nullptr && local_id != INVALID_ID; }
|
||||
|
||||
WaylandObject *get() { return is_valid() ? client->get_object(local_id) : nullptr; }
|
||||
constexpr Client *get_client() const { return client; }
|
||||
constexpr uint32_t get_local_id() const { return local_id; }
|
||||
uint32_t get_global_id() const { return (is_valid() && client->global_ids.has(local_id)) ? client->global_ids[local_id].id : INVALID_ID; }
|
||||
};
|
||||
|
||||
struct WaylandSeatInstanceData : WaylandObjectData {
|
||||
uint32_t wl_keyboard_id = INVALID_ID;
|
||||
uint32_t wl_pointer_id = INVALID_ID;
|
||||
};
|
||||
|
||||
struct WaylandSeatGlobalData : WaylandObjectData {
|
||||
uint32_t capabilities = 0;
|
||||
|
||||
uint32_t pointed_surface_id = INVALID_ID;
|
||||
uint32_t focused_surface_id = INVALID_ID;
|
||||
};
|
||||
|
||||
struct WaylandKeyboardData : WaylandObjectData {
|
||||
uint32_t wl_seat_id = INVALID_ID;
|
||||
};
|
||||
|
||||
struct WaylandPointerData : WaylandObjectData {
|
||||
uint32_t wl_seat_id = INVALID_ID;
|
||||
};
|
||||
|
||||
struct WaylandSurfaceData : WaylandObjectData {
|
||||
Client *client = nullptr;
|
||||
LocalObjectHandle role_object_handle;
|
||||
};
|
||||
|
||||
struct XdgSurfaceData : WaylandObjectData {
|
||||
uint32_t wl_surface_id = INVALID_ID;
|
||||
};
|
||||
|
||||
struct WaylandSubsurfaceData : WaylandObjectData {
|
||||
Point2i position;
|
||||
};
|
||||
|
||||
struct XdgToplevelData : WaylandObjectData {
|
||||
LocalObjectHandle xdg_surface_handle;
|
||||
LocalObjectHandle parent_handle;
|
||||
uint32_t wl_subsurface_id = INVALID_ID;
|
||||
|
||||
Size2i size;
|
||||
|
||||
bool configured = false;
|
||||
|
||||
constexpr bool is_embedded() const { return wl_subsurface_id != INVALID_ID; }
|
||||
};
|
||||
|
||||
struct XdgPopupData : WaylandObjectData {
|
||||
LocalObjectHandle parent_handle;
|
||||
};
|
||||
|
||||
struct XdgPositionerData : WaylandObjectData {
|
||||
Rect2i anchor_rect;
|
||||
};
|
||||
|
||||
struct EmbeddedClientData : WaylandObjectData {
|
||||
Client *client = nullptr;
|
||||
bool disconnected = false;
|
||||
};
|
||||
|
||||
struct RegistryGlobalInfo {
|
||||
const struct wl_interface *interface = nullptr;
|
||||
uint32_t version = 0;
|
||||
uint32_t compositor_name = 0;
|
||||
|
||||
// The specs requires for us to ignore requests for destroyed global
|
||||
// objects until all instances are gone, to avoid races.
|
||||
bool destroyed = false;
|
||||
int instance_counter = 0;
|
||||
|
||||
// Key is version.
|
||||
HashMap<uint32_t, uint32_t> reusable_objects;
|
||||
|
||||
WaylandObjectData *data = nullptr;
|
||||
};
|
||||
|
||||
// These are the interfaces that the embedder understands and exposes. We do
|
||||
// not implement handlers for all of them (that's the point), but we need to
|
||||
// list them anyways to query their signatures at runtime, which include file
|
||||
// descriptors count. Additionally, even if we could go without specifying
|
||||
// them, having a "known good" list avoids unpleasant incompatibilities with
|
||||
// future compositors.
|
||||
const static constexpr struct wl_interface *interfaces[] = {
|
||||
// wayland
|
||||
&wl_buffer_interface,
|
||||
&wl_callback_interface,
|
||||
&wl_compositor_interface,
|
||||
&wl_data_device_interface,
|
||||
&wl_data_device_manager_interface,
|
||||
&wl_data_offer_interface,
|
||||
&wl_data_source_interface,
|
||||
&wl_display_interface,
|
||||
&wl_keyboard_interface,
|
||||
&wl_output_interface,
|
||||
&wl_pointer_interface,
|
||||
&wl_region_interface,
|
||||
&wl_registry_interface,
|
||||
&wl_seat_interface,
|
||||
//&wl_shell_interface, // Deprecated.
|
||||
//&wl_shell_surface_interface, // Deprecated.
|
||||
&wl_shm_interface,
|
||||
&wl_shm_pool_interface,
|
||||
&wl_subcompositor_interface,
|
||||
&wl_subsurface_interface,
|
||||
&wl_surface_interface,
|
||||
//&wl_touch_interface, // Unused (at the moment).
|
||||
|
||||
// xdg-shell
|
||||
&xdg_wm_base_interface,
|
||||
&xdg_positioner_interface,
|
||||
&xdg_surface_interface,
|
||||
&xdg_toplevel_interface,
|
||||
&xdg_popup_interface,
|
||||
|
||||
// linux-dmabuf-v1
|
||||
&zwp_linux_dmabuf_v1_interface,
|
||||
&zwp_linux_buffer_params_v1_interface,
|
||||
&zwp_linux_dmabuf_feedback_v1_interface,
|
||||
|
||||
// linux-explicit-synchronization-unstable-v1
|
||||
&zwp_linux_explicit_synchronization_v1_interface,
|
||||
&zwp_linux_surface_synchronization_v1_interface,
|
||||
&zwp_linux_buffer_release_v1_interface,
|
||||
|
||||
// fractional-scale
|
||||
&wp_fractional_scale_manager_v1_interface,
|
||||
&wp_fractional_scale_v1_interface,
|
||||
|
||||
// idle-inhibit
|
||||
&zwp_idle_inhibit_manager_v1_interface,
|
||||
&zwp_idle_inhibitor_v1_interface,
|
||||
|
||||
// pointer-constraints
|
||||
&zwp_pointer_constraints_v1_interface,
|
||||
&zwp_locked_pointer_v1_interface,
|
||||
&zwp_confined_pointer_v1_interface,
|
||||
|
||||
// pointer-gestures
|
||||
&zwp_pointer_gestures_v1_interface,
|
||||
&zwp_pointer_gesture_swipe_v1_interface,
|
||||
&zwp_pointer_gesture_pinch_v1_interface,
|
||||
&zwp_pointer_gesture_hold_v1_interface,
|
||||
|
||||
// primary-selection
|
||||
&zwp_primary_selection_device_manager_v1_interface,
|
||||
&zwp_primary_selection_device_v1_interface,
|
||||
&zwp_primary_selection_offer_v1_interface,
|
||||
&zwp_primary_selection_source_v1_interface,
|
||||
|
||||
// relative-pointer
|
||||
&zwp_relative_pointer_manager_v1_interface,
|
||||
&zwp_relative_pointer_v1_interface,
|
||||
|
||||
// tablet
|
||||
// TODO: Needs some extra work
|
||||
//&zwp_tablet_manager_v2_interface,
|
||||
//&zwp_tablet_seat_v2_interface,
|
||||
//&zwp_tablet_tool_v2_interface,
|
||||
//&zwp_tablet_v2_interface,
|
||||
//&zwp_tablet_pad_ring_v2_interface,
|
||||
//&zwp_tablet_pad_strip_v2_interface,
|
||||
//&zwp_tablet_pad_group_v2_interface,
|
||||
//&zwp_tablet_pad_v2_interface,
|
||||
|
||||
// text-input
|
||||
&zwp_text_input_v3_interface,
|
||||
&zwp_text_input_manager_v3_interface,
|
||||
|
||||
// viewporter
|
||||
&wp_viewporter_interface,
|
||||
&wp_viewport_interface,
|
||||
|
||||
// xdg-activation
|
||||
&xdg_activation_v1_interface,
|
||||
&xdg_activation_token_v1_interface,
|
||||
|
||||
// xdg-decoration
|
||||
&zxdg_decoration_manager_v1_interface,
|
||||
&zxdg_toplevel_decoration_v1_interface,
|
||||
|
||||
// xdg-foreign
|
||||
&zxdg_exporter_v1_interface,
|
||||
&zxdg_importer_v1_interface,
|
||||
|
||||
// xdg-foreign-v1
|
||||
&zxdg_exporter_v1_interface,
|
||||
&zxdg_importer_v1_interface,
|
||||
|
||||
// xdg-foreign-v2
|
||||
&zxdg_exporter_v2_interface,
|
||||
&zxdg_importer_v2_interface,
|
||||
|
||||
// xdg-shell
|
||||
&xdg_wm_base_interface,
|
||||
&xdg_positioner_interface,
|
||||
&xdg_surface_interface,
|
||||
&xdg_toplevel_interface,
|
||||
&xdg_popup_interface,
|
||||
|
||||
// xdg-system-bell
|
||||
&xdg_system_bell_v1_interface,
|
||||
|
||||
// xdg-toplevel-icon-v1
|
||||
&xdg_toplevel_icon_manager_v1_interface,
|
||||
&xdg_toplevel_icon_v1_interface,
|
||||
|
||||
// wp-cursor-shape-v1
|
||||
&wp_cursor_shape_manager_v1_interface,
|
||||
|
||||
// wayland-drm
|
||||
&wl_drm_interface,
|
||||
|
||||
// linux-drm-syncobj-v1
|
||||
&wp_linux_drm_syncobj_manager_v1_interface,
|
||||
&wp_linux_drm_syncobj_surface_v1_interface,
|
||||
&wp_linux_drm_syncobj_timeline_v1_interface,
|
||||
|
||||
// fifo-v1
|
||||
&wp_fifo_manager_v1_interface,
|
||||
&wp_fifo_v1_interface,
|
||||
|
||||
// commit-timing-v1
|
||||
&wp_commit_timing_manager_v1_interface,
|
||||
&wp_commit_timer_v1_interface,
|
||||
|
||||
// tearing-control-v1
|
||||
&wp_tearing_control_manager_v1_interface,
|
||||
&wp_tearing_control_v1_interface,
|
||||
|
||||
// Our custom things.
|
||||
&godot_embedding_compositor_interface,
|
||||
&godot_embedded_client_interface,
|
||||
};
|
||||
|
||||
// These interfaces will not be reported to embedded clients. This includes
|
||||
// stuff that interacts with toplevels or other emulated objects that would
|
||||
// have been filtered out manually anyways.
|
||||
HashSet<const struct wl_interface *> embedded_interface_deny_list = HashSet({
|
||||
&zxdg_decoration_manager_v1_interface,
|
||||
&zxdg_decoration_manager_v1_interface,
|
||||
&zxdg_exporter_v1_interface,
|
||||
&zxdg_exporter_v2_interface,
|
||||
&xdg_toplevel_icon_manager_v1_interface,
|
||||
&godot_embedding_compositor_interface,
|
||||
});
|
||||
|
||||
static constexpr uint32_t INVALID_ID = 0;
|
||||
static constexpr uint32_t DISPLAY_ID = 1;
|
||||
static constexpr uint32_t REGISTRY_ID = 2;
|
||||
|
||||
int proxy_socket = -1;
|
||||
int compositor_socket = -1;
|
||||
|
||||
// NOTE: First element must be the listening socket! This allows us to process
|
||||
// it last, cleaning up closed sockets before it reuses their handles.
|
||||
LocalVector<struct pollfd> pollfds;
|
||||
|
||||
// Key is socket.
|
||||
AHashMap<int, Client> clients;
|
||||
|
||||
Client *main_client = nullptr;
|
||||
|
||||
PooledList<WaylandObject> objects;
|
||||
// Proxies allocated by the compositor. Their ID starts from 0xff000000.
|
||||
LocalVector<WaylandObject> server_objects;
|
||||
|
||||
uint32_t wl_compositor_id = 0;
|
||||
uint32_t wl_subcompositor_id = 0;
|
||||
uint32_t main_toplevel_id = 0;
|
||||
uint32_t xdg_wm_base_id = 0;
|
||||
|
||||
// Global id to name
|
||||
HashMap<uint32_t, uint32_t> registry_globals_names;
|
||||
|
||||
HashMap<uint32_t, RegistryGlobalInfo> registry_globals;
|
||||
uint32_t registry_globals_counter = 0;
|
||||
|
||||
uint32_t godot_embedding_compositor_name = 0;
|
||||
|
||||
LocalVector<uint32_t> wl_seat_names;
|
||||
|
||||
Thread proxy_thread;
|
||||
|
||||
List<int> client_fds;
|
||||
List<int> compositor_fds;
|
||||
|
||||
uint32_t serial_counter = 0;
|
||||
uint32_t configure_serial_counter = 0;
|
||||
|
||||
uint32_t sync_callback_id = 0;
|
||||
|
||||
Ref<DirAccess> runtime_dir;
|
||||
int lock_fd = -1;
|
||||
String socket_path;
|
||||
String socket_lock_path;
|
||||
|
||||
LocalVector<uint32_t> msg_buf;
|
||||
LocalVector<uint8_t> ancillary_buf;
|
||||
|
||||
SafeFlag thread_done;
|
||||
|
||||
static size_t wl_array_word_offset(uint32_t p_size);
|
||||
const static struct wl_interface *wl_interface_from_string(const char *name, size_t size);
|
||||
static int wl_interface_get_destructor_opcode(const struct wl_interface *p_iface, uint32_t p_version);
|
||||
|
||||
static Error send_raw_message(int p_socket, std::initializer_list<struct iovec> p_vecs, const LocalVector<int> &p_fds = LocalVector<int>());
|
||||
|
||||
static Error send_wayland_message(int p_socket, uint32_t p_id, uint32_t p_opcode, const uint32_t *p_args, const size_t p_args_words);
|
||||
static Error send_wayland_message(ProxyDirection p_direction, int p_socket, uint32_t p_id, const struct wl_interface &p_interface, uint32_t p_opcode, const LocalVector<union wl_argument> &p_args);
|
||||
|
||||
// Utility aliases.
|
||||
|
||||
static Error send_wayland_message(int p_socket, uint32_t p_id, uint32_t p_opcode, std::initializer_list<uint32_t> p_args) {
|
||||
return send_wayland_message(p_socket, p_id, p_opcode, p_args.begin(), p_args.size());
|
||||
}
|
||||
|
||||
static Error send_wayland_method(int p_socket, uint32_t p_id, const struct wl_interface &p_interface, uint32_t p_opcode, const LocalVector<union wl_argument> &p_args) {
|
||||
return send_wayland_message(ProxyDirection::COMPOSITOR, p_socket, p_id, p_interface, p_opcode, p_args);
|
||||
}
|
||||
|
||||
static Error send_wayland_event(int p_socket, uint32_t p_id, const struct wl_interface &p_interface, uint32_t p_opcode, const LocalVector<union wl_argument> &p_args) {
|
||||
return send_wayland_message(ProxyDirection::CLIENT, p_socket, p_id, p_interface, p_opcode, p_args);
|
||||
}
|
||||
|
||||
// Closes the socket.
|
||||
static void socket_error(int p_socket, uint32_t p_object_id, uint32_t p_code, const String &p_message);
|
||||
|
||||
// NOTE: Yes, in our case object arguments are actually uints for now.
|
||||
// Best way I found to reuse the Wayland stuff. Might need to make our
|
||||
// own eventually.
|
||||
static constexpr union wl_argument wl_arg_int(int32_t p_value) {
|
||||
union wl_argument arg = {};
|
||||
arg.i = p_value;
|
||||
return arg;
|
||||
}
|
||||
static constexpr union wl_argument wl_arg_uint(uint32_t p_value) {
|
||||
union wl_argument arg = {};
|
||||
arg.u = p_value;
|
||||
return arg;
|
||||
}
|
||||
static constexpr union wl_argument wl_arg_fixed(wl_fixed_t p_value) {
|
||||
union wl_argument arg = {};
|
||||
arg.f = p_value;
|
||||
return arg;
|
||||
}
|
||||
static constexpr union wl_argument wl_arg_string(const char *p_value) {
|
||||
union wl_argument arg = {};
|
||||
arg.s = p_value;
|
||||
return arg;
|
||||
}
|
||||
static constexpr union wl_argument wl_arg_object(uint32_t p_value) {
|
||||
union wl_argument arg = {};
|
||||
arg.u = p_value;
|
||||
return arg;
|
||||
}
|
||||
static constexpr union wl_argument wl_arg_new_id(uint32_t p_value) {
|
||||
union wl_argument arg = {};
|
||||
arg.n = p_value;
|
||||
return arg;
|
||||
}
|
||||
|
||||
uint32_t new_object(const struct wl_interface *p_interface, int p_version = 1, WaylandObjectData *p_data = nullptr);
|
||||
WaylandObject *new_server_object(uint32_t p_global_id, const struct wl_interface *p_interface, int p_version = 1, WaylandObjectData *p_data = nullptr);
|
||||
|
||||
void poll_sockets();
|
||||
|
||||
int allocate_global_id();
|
||||
|
||||
bool global_surface_is_window(uint32_t p_global_surface_id);
|
||||
|
||||
WaylandObject *get_object(uint32_t id);
|
||||
Error delete_object(uint32_t id);
|
||||
|
||||
void cleanup_socket(int p_socket);
|
||||
|
||||
void sync();
|
||||
|
||||
uint32_t wl_registry_bind(uint32_t p_registry_id, uint32_t p_name, int p_version);
|
||||
|
||||
void seat_name_enter_surface(uint32_t p_seat_name, uint32_t p_global_surface_id);
|
||||
void seat_name_leave_surface(uint32_t p_seat_name, uint32_t p_global_surface_id);
|
||||
|
||||
MessageStatus handle_request(LocalObjectHandle p_object, uint32_t p_opcode, const uint32_t *msg_data, size_t msg_len);
|
||||
MessageStatus handle_event(uint32_t p_global_id, LocalObjectHandle p_local_handle, uint32_t p_opcode, const uint32_t *msg_data, size_t msg_len);
|
||||
|
||||
void shutdown();
|
||||
|
||||
bool handle_generic_msg(Client *client, const WaylandObject *p_object, const struct wl_message *message, const struct msg_info *info, uint32_t *buf, uint32_t instance_id = INVALID_ID);
|
||||
Error handle_msg_info(Client *client, const struct msg_info *info, uint32_t *buf, int *fds_requested);
|
||||
Error handle_sock(int p_fd);
|
||||
void handle_fd(int p_fd, int p_revents);
|
||||
|
||||
static void _thread_loop(void *p_data);
|
||||
|
||||
public:
|
||||
// Returns path to socket.
|
||||
Error init();
|
||||
|
||||
String get_socket_path() const { return socket_path; }
|
||||
|
||||
~WaylandEmbedder();
|
||||
};
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
#endif // WAYLAND_ENABLED
|
||||
@@ -662,6 +662,13 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
|
||||
if (strcmp(interface, FIFO_INTERFACE_NAME) == 0) {
|
||||
registry->wp_fifo_manager_name = name;
|
||||
}
|
||||
|
||||
if (strcmp(interface, godot_embedding_compositor_interface.name) == 0) {
|
||||
registry->godot_embedding_compositor = (struct godot_embedding_compositor *)wl_registry_bind(wl_registry, name, &godot_embedding_compositor_interface, 1);
|
||||
registry->godot_embedding_compositor_name = name;
|
||||
|
||||
godot_embedding_compositor_add_listener(registry->godot_embedding_compositor, &godot_embedding_compositor_listener, memnew(EmbeddingCompositorState));
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) {
|
||||
@@ -1092,6 +1099,25 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry
|
||||
if (name == registry->wp_fifo_manager_name) {
|
||||
registry->wp_fifo_manager_name = 0;
|
||||
}
|
||||
|
||||
if (name == registry->godot_embedding_compositor_name) {
|
||||
registry->godot_embedding_compositor_name = 0;
|
||||
|
||||
EmbeddingCompositorState *es = godot_embedding_compositor_get_state(registry->godot_embedding_compositor);
|
||||
ERR_FAIL_NULL(es);
|
||||
|
||||
es->mapped_clients.clear();
|
||||
|
||||
for (struct godot_embedded_client *client : es->clients) {
|
||||
godot_embedded_client_destroy(client);
|
||||
}
|
||||
es->clients.clear();
|
||||
|
||||
memdelete(es);
|
||||
|
||||
godot_embedding_compositor_destroy(registry->godot_embedding_compositor);
|
||||
registry->godot_embedding_compositor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandThread::_wl_surface_on_enter(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output) {
|
||||
@@ -2064,6 +2090,8 @@ void WaylandThread::_wl_keyboard_on_keymap(void *data, struct wl_keyboard *wl_ke
|
||||
|
||||
xkb_state_unref(ss->xkb_state);
|
||||
ss->xkb_state = xkb_state_new(ss->xkb_keymap);
|
||||
|
||||
xkb_state_update_mask(ss->xkb_state, ss->mods_depressed, ss->mods_latched, ss->mods_locked, 0, 0, ss->current_layout_index);
|
||||
}
|
||||
|
||||
void WaylandThread::_wl_keyboard_on_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
|
||||
@@ -2124,6 +2152,15 @@ void WaylandThread::_wl_keyboard_on_leave(void *data, struct wl_keyboard *wl_key
|
||||
msg->event = DisplayServer::WINDOW_EVENT_FOCUS_OUT;
|
||||
wayland_thread->push_message(msg);
|
||||
|
||||
ss->shift_pressed = false;
|
||||
ss->ctrl_pressed = false;
|
||||
ss->alt_pressed = false;
|
||||
ss->meta_pressed = false;
|
||||
|
||||
if (ss->xkb_state != nullptr) {
|
||||
xkb_state_update_mask(ss->xkb_state, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
DEBUG_LOG_WAYLAND_THREAD(vformat("Keyboard unfocused window %d.", ws->id));
|
||||
}
|
||||
|
||||
@@ -2177,14 +2214,21 @@ void WaylandThread::_wl_keyboard_on_modifiers(void *data, struct wl_keyboard *wl
|
||||
SeatState *ss = (SeatState *)data;
|
||||
ERR_FAIL_NULL(ss);
|
||||
|
||||
xkb_state_update_mask(ss->xkb_state, mods_depressed, mods_latched, mods_locked, ss->current_layout_index, ss->current_layout_index, group);
|
||||
|
||||
ss->shift_pressed = xkb_state_mod_name_is_active(ss->xkb_state, XKB_MOD_NAME_SHIFT, XKB_STATE_MODS_DEPRESSED);
|
||||
ss->ctrl_pressed = xkb_state_mod_name_is_active(ss->xkb_state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_DEPRESSED);
|
||||
ss->alt_pressed = xkb_state_mod_name_is_active(ss->xkb_state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_DEPRESSED);
|
||||
ss->meta_pressed = xkb_state_mod_name_is_active(ss->xkb_state, XKB_MOD_NAME_LOGO, XKB_STATE_MODS_DEPRESSED);
|
||||
|
||||
ss->mods_depressed = mods_depressed;
|
||||
ss->mods_latched = mods_latched;
|
||||
ss->mods_locked = mods_locked;
|
||||
ss->current_layout_index = group;
|
||||
|
||||
if (ss->xkb_state == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
xkb_state_update_mask(ss->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||
|
||||
ss->shift_pressed = xkb_state_mod_name_is_active(ss->xkb_state, XKB_MOD_NAME_SHIFT, XKB_STATE_MODS_EFFECTIVE);
|
||||
ss->ctrl_pressed = xkb_state_mod_name_is_active(ss->xkb_state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE);
|
||||
ss->alt_pressed = xkb_state_mod_name_is_active(ss->xkb_state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_EFFECTIVE);
|
||||
ss->meta_pressed = xkb_state_mod_name_is_active(ss->xkb_state, XKB_MOD_NAME_LOGO, XKB_STATE_MODS_EFFECTIVE);
|
||||
}
|
||||
|
||||
void WaylandThread::_wl_keyboard_on_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay) {
|
||||
@@ -3036,15 +3080,82 @@ void WaylandThread::_xdg_activation_token_on_done(void *data, struct xdg_activat
|
||||
DEBUG_LOG_WAYLAND_THREAD(vformat("Received activation token and requested window activation."));
|
||||
}
|
||||
|
||||
void WaylandThread::_godot_embedding_compositor_on_client(void *data, struct godot_embedding_compositor *godot_embedding_compositor, struct godot_embedded_client *godot_embedded_client, int32_t pid) {
|
||||
EmbeddingCompositorState *state = (EmbeddingCompositorState *)data;
|
||||
ERR_FAIL_NULL(state);
|
||||
|
||||
EmbeddedClientState *client_state = memnew(EmbeddedClientState);
|
||||
client_state->embedding_compositor = godot_embedding_compositor;
|
||||
client_state->pid = pid;
|
||||
godot_embedded_client_add_listener(godot_embedded_client, &godot_embedded_client_listener, client_state);
|
||||
|
||||
DEBUG_LOG_WAYLAND_THREAD(vformat("New client %d.", pid));
|
||||
state->clients.push_back(godot_embedded_client);
|
||||
}
|
||||
|
||||
void WaylandThread::_godot_embedded_client_on_disconnected(void *data, struct godot_embedded_client *godot_embedded_client) {
|
||||
EmbeddedClientState *state = (EmbeddedClientState *)data;
|
||||
ERR_FAIL_NULL(state);
|
||||
|
||||
EmbeddingCompositorState *ecomp_state = godot_embedding_compositor_get_state(state->embedding_compositor);
|
||||
ERR_FAIL_NULL(ecomp_state);
|
||||
|
||||
ecomp_state->clients.erase_unordered(godot_embedded_client);
|
||||
ecomp_state->mapped_clients.erase(state->pid);
|
||||
|
||||
memfree(state);
|
||||
godot_embedded_client_destroy(godot_embedded_client);
|
||||
|
||||
DEBUG_LOG_WAYLAND_THREAD(vformat("Client %d disconnected.", state->pid));
|
||||
}
|
||||
|
||||
void WaylandThread::_godot_embedded_client_on_window_embedded(void *data, struct godot_embedded_client *godot_embedded_client) {
|
||||
EmbeddedClientState *state = (EmbeddedClientState *)data;
|
||||
ERR_FAIL_NULL(state);
|
||||
|
||||
EmbeddingCompositorState *ecomp_state = godot_embedding_compositor_get_state(state->embedding_compositor);
|
||||
ERR_FAIL_NULL(ecomp_state);
|
||||
|
||||
state->window_mapped = true;
|
||||
|
||||
ERR_FAIL_COND_MSG(ecomp_state->mapped_clients.has(state->pid), "More than one Wayland client per PID tried to create a window.");
|
||||
|
||||
ecomp_state->mapped_clients[state->pid] = godot_embedded_client;
|
||||
}
|
||||
|
||||
void WaylandThread::_godot_embedded_client_on_window_focus_in(void *data, struct godot_embedded_client *godot_embedded_client) {
|
||||
EmbeddedClientState *state = (EmbeddedClientState *)data;
|
||||
ERR_FAIL_NULL(state);
|
||||
|
||||
EmbeddingCompositorState *ecomp_state = godot_embedding_compositor_get_state(state->embedding_compositor);
|
||||
ERR_FAIL_NULL(ecomp_state);
|
||||
|
||||
ecomp_state->focused_pid = state->pid;
|
||||
DEBUG_LOG_WAYLAND_THREAD(vformat("Embedded client pid %d focus in", state->pid));
|
||||
}
|
||||
|
||||
void WaylandThread::_godot_embedded_client_on_window_focus_out(void *data, struct godot_embedded_client *godot_embedded_client) {
|
||||
EmbeddedClientState *state = (EmbeddedClientState *)data;
|
||||
ERR_FAIL_NULL(state);
|
||||
|
||||
EmbeddingCompositorState *ecomp_state = godot_embedding_compositor_get_state(state->embedding_compositor);
|
||||
ERR_FAIL_NULL(ecomp_state);
|
||||
|
||||
ecomp_state->focused_pid = -1;
|
||||
DEBUG_LOG_WAYLAND_THREAD(vformat("Embedded client pid %d focus out", state->pid));
|
||||
}
|
||||
|
||||
// NOTE: This must be started after a valid wl_display is loaded.
|
||||
void WaylandThread::_poll_events_thread(void *p_data) {
|
||||
Thread::set_name("Wayland Events");
|
||||
|
||||
ThreadData *data = (ThreadData *)p_data;
|
||||
ERR_FAIL_NULL(data);
|
||||
ERR_FAIL_NULL(data->wl_display);
|
||||
|
||||
struct pollfd poll_fd;
|
||||
struct pollfd poll_fd = {};
|
||||
poll_fd.fd = wl_display_get_fd(data->wl_display);
|
||||
poll_fd.events = POLLIN | POLLHUP;
|
||||
poll_fd.events = POLLIN;
|
||||
|
||||
while (true) {
|
||||
// Empty the event queue while it's full.
|
||||
@@ -3188,6 +3299,15 @@ WaylandThread::OfferState *WaylandThread::wp_primary_selection_offer_get_offer_s
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WaylandThread::EmbeddingCompositorState *WaylandThread::godot_embedding_compositor_get_state(struct godot_embedding_compositor *p_compositor) {
|
||||
// NOTE: No need for tag check as it's a "fake" interface - nothing else exposes it.
|
||||
if (p_compositor) {
|
||||
return (EmbeddingCompositorState *)godot_embedding_compositor_get_user_data(p_compositor);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This is implemented as a method because this is the simplest way of
|
||||
// accounting for dynamic output scale changes.
|
||||
int WaylandThread::window_state_get_preferred_buffer_scale(WindowState *p_ws) {
|
||||
@@ -3356,15 +3476,20 @@ void WaylandThread::seat_state_lock_pointer(SeatState *p_ss) {
|
||||
ERR_FAIL_NULL(p_ss);
|
||||
|
||||
if (p_ss->wl_pointer == nullptr) {
|
||||
WARN_PRINT("Can't lock - no pointer?");
|
||||
return;
|
||||
}
|
||||
|
||||
if (registry.wp_pointer_constraints == nullptr) {
|
||||
WARN_PRINT("Can't lock - no constraints global.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_ss->wp_locked_pointer == nullptr) {
|
||||
struct wl_surface *locked_surface = window_get_wl_surface(p_ss->pointer_data.last_pointed_id);
|
||||
if (locked_surface == nullptr) {
|
||||
locked_surface = window_get_wl_surface(DisplayServer::MAIN_WINDOW_ID);
|
||||
}
|
||||
ERR_FAIL_NULL(locked_surface);
|
||||
|
||||
p_ss->wp_locked_pointer = zwp_pointer_constraints_v1_lock_pointer(registry.wp_pointer_constraints, locked_surface, p_ss->wl_pointer, nullptr, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
||||
@@ -4445,7 +4570,52 @@ Error WaylandThread::init() {
|
||||
|
||||
KeyMappingXKB::initialize();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
String embedder_socket_path;
|
||||
|
||||
bool embedder_enabled = true;
|
||||
|
||||
if (OS::get_singleton()->get_environment("GODOT_WAYLAND_DISABLE_EMBEDDER") == "1") {
|
||||
print_verbose("Disabling Wayland embedder as per GODOT_WAYLAND_DISABLE_EMBEDDER.");
|
||||
embedder_enabled = false;
|
||||
}
|
||||
|
||||
if (embedder_enabled && Engine::get_singleton()->is_editor_hint() && !Engine::get_singleton()->is_project_manager_hint()) {
|
||||
print_verbose("Initializing Wayland embedder.");
|
||||
Error embedder_status = embedder.init();
|
||||
ERR_FAIL_COND_V_MSG(embedder_status != OK, ERR_CANT_CREATE, "Can't initialize Wayland embedder.");
|
||||
|
||||
embedder_socket_path = embedder.get_socket_path();
|
||||
ERR_FAIL_COND_V_MSG(embedder_socket_path.is_empty(), ERR_CANT_CREATE, "Wayland embedder returned invalid path.");
|
||||
|
||||
OS::get_singleton()->set_environment("GODOT_WAYLAND_DISPLAY", embedder_socket_path);
|
||||
|
||||
// Debug
|
||||
if (OS::get_singleton()->get_environment("GODOT_DEBUG_EMBEDDER_SINGLE_INSTANCE") == "1") {
|
||||
print_line("Pausing as per GODOT_DEBUG_EMBEDDER_SINGLE_INSTANCE.");
|
||||
pause();
|
||||
}
|
||||
} else if (Engine::get_singleton()->is_embedded_in_editor()) {
|
||||
embedder_socket_path = OS::get_singleton()->get_environment("GODOT_WAYLAND_DISPLAY");
|
||||
|
||||
#if 0
|
||||
// Debug
|
||||
OS::get_singleton()->set_environment("WAYLAND_DEBUG", "1");
|
||||
int fd = open("/tmp/gdembedded.log", O_CREAT | O_RDWR, 0666);
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (embedder_socket_path.is_empty()) {
|
||||
print_verbose("Connecting to the default Wayland display.");
|
||||
wl_display = wl_display_connect(nullptr);
|
||||
} else {
|
||||
print_verbose("Connecting to the Wayland embedder display.");
|
||||
wl_display = wl_display_connect(embedder_socket_path.utf8().get_data());
|
||||
}
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
ERR_FAIL_NULL_V_MSG(wl_display, ERR_CANT_CREATE, "Can't connect to a Wayland display.");
|
||||
|
||||
thread_data.wl_display = wl_display;
|
||||
@@ -4465,6 +4635,8 @@ Error WaylandThread::init() {
|
||||
ERR_FAIL_NULL_V_MSG(registry.wl_compositor, ERR_UNAVAILABLE, "Can't obtain the Wayland compositor global.");
|
||||
ERR_FAIL_NULL_V_MSG(registry.xdg_wm_base, ERR_UNAVAILABLE, "Can't obtain the Wayland XDG shell global.");
|
||||
|
||||
// Embedded games can't access the decoration and icon protocol.
|
||||
if (!Engine::get_singleton()->is_embedded_in_editor()) {
|
||||
if (!registry.xdg_decoration_manager) {
|
||||
#ifdef LIBDECOR_ENABLED
|
||||
WARN_PRINT("Can't obtain the XDG decoration manager. Libdecor will be used for drawing CSDs, if available.");
|
||||
@@ -4473,6 +4645,11 @@ Error WaylandThread::init() {
|
||||
#endif // LIBDECOR_ENABLED
|
||||
}
|
||||
|
||||
if (!registry.xdg_toplevel_icon_manager_name) {
|
||||
WARN_PRINT("xdg-toplevel-icon protocol not found! Cannot set window icon.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!registry.xdg_activation) {
|
||||
WARN_PRINT("Can't obtain the XDG activation global. Attention requesting won't work!");
|
||||
}
|
||||
@@ -4487,10 +4664,6 @@ Error WaylandThread::init() {
|
||||
WARN_PRINT("FIFO protocol not found! Frame pacing will be degraded.");
|
||||
}
|
||||
|
||||
if (!registry.xdg_toplevel_icon_manager_name) {
|
||||
WARN_PRINT("xdg-toplevel-icon protocol not found! Cannot set window icon.");
|
||||
}
|
||||
|
||||
// Wait for seat capabilities.
|
||||
wl_display_roundtrip(wl_display);
|
||||
|
||||
@@ -5010,6 +5183,17 @@ bool WaylandThread::is_suspended() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct godot_embedding_compositor *WaylandThread::get_embedding_compositor() {
|
||||
return registry.godot_embedding_compositor;
|
||||
}
|
||||
|
||||
OS::ProcessID WaylandThread::embedded_compositor_get_focused_pid() {
|
||||
EmbeddingCompositorState *ecomp_state = godot_embedding_compositor_get_state(registry.godot_embedding_compositor);
|
||||
ERR_FAIL_NULL_V(ecomp_state, -1);
|
||||
|
||||
return ecomp_state->focused_pid;
|
||||
}
|
||||
|
||||
void WaylandThread::destroy() {
|
||||
if (!initialized) {
|
||||
return;
|
||||
@@ -5045,6 +5229,10 @@ void WaylandThread::destroy() {
|
||||
}
|
||||
#endif // LIBDECOR_ENABLED
|
||||
|
||||
if (ws.xdg_toplevel_decoration) {
|
||||
zxdg_toplevel_decoration_v1_destroy(ws.xdg_toplevel_decoration);
|
||||
}
|
||||
|
||||
if (ws.xdg_toplevel) {
|
||||
xdg_toplevel_destroy(ws.xdg_toplevel);
|
||||
}
|
||||
@@ -5132,6 +5320,22 @@ void WaylandThread::destroy() {
|
||||
wl_output_destroy(wl_output);
|
||||
}
|
||||
|
||||
if (registry.godot_embedding_compositor) {
|
||||
EmbeddingCompositorState *es = godot_embedding_compositor_get_state(registry.godot_embedding_compositor);
|
||||
ERR_FAIL_NULL(es);
|
||||
|
||||
es->mapped_clients.clear();
|
||||
|
||||
for (struct godot_embedded_client *client : es->clients) {
|
||||
godot_embedded_client_destroy(client);
|
||||
}
|
||||
es->clients.clear();
|
||||
|
||||
memdelete(es);
|
||||
|
||||
godot_embedding_compositor_destroy(registry.godot_embedding_compositor);
|
||||
}
|
||||
|
||||
if (wl_cursor_theme) {
|
||||
wl_cursor_theme_destroy(wl_cursor_theme);
|
||||
}
|
||||
@@ -5212,6 +5416,8 @@ void WaylandThread::destroy() {
|
||||
wl_registry_destroy(wl_registry);
|
||||
}
|
||||
|
||||
wl_display_roundtrip(wl_display);
|
||||
|
||||
if (wl_display) {
|
||||
wl_display_disconnect(wl_display);
|
||||
}
|
||||
|
||||
@@ -72,6 +72,8 @@
|
||||
#include "wayland/protocol/xdg_system_bell.gen.h"
|
||||
#include "wayland/protocol/xdg_toplevel_icon.gen.h"
|
||||
|
||||
#include "wayland/protocol/godot_embedding_compositor.gen.h"
|
||||
|
||||
// NOTE: Deprecated.
|
||||
#include "wayland/protocol/xdg_foreign_v1.gen.h"
|
||||
|
||||
@@ -86,6 +88,8 @@
|
||||
#include "core/os/thread.h"
|
||||
#include "servers/display/display_server.h"
|
||||
|
||||
#include "wayland_embedder.h"
|
||||
|
||||
class WaylandThread {
|
||||
public:
|
||||
// Messages used for exchanging information between Godot's and Wayland's thread.
|
||||
@@ -228,6 +232,9 @@ public:
|
||||
// We're really not meant to use this one directly but we still need to know
|
||||
// whether it's available.
|
||||
uint32_t wp_fifo_manager_name = 0;
|
||||
|
||||
struct godot_embedding_compositor *godot_embedding_compositor = nullptr;
|
||||
uint32_t godot_embedding_compositor_name = 0;
|
||||
};
|
||||
|
||||
// General Wayland-specific states. Shouldn't be accessed directly.
|
||||
@@ -477,6 +484,10 @@ public:
|
||||
uint64_t last_repeat_start_msec = 0;
|
||||
uint64_t last_repeat_msec = 0;
|
||||
|
||||
uint32_t mods_depressed = 0;
|
||||
uint32_t mods_latched = 0;
|
||||
uint32_t mods_locked = 0;
|
||||
|
||||
bool shift_pressed = false;
|
||||
bool ctrl_pressed = false;
|
||||
bool alt_pressed = false;
|
||||
@@ -529,6 +540,22 @@ public:
|
||||
Point2i hotspot;
|
||||
};
|
||||
|
||||
struct EmbeddingCompositorState {
|
||||
LocalVector<struct godot_embedded_client *> clients;
|
||||
|
||||
// Only a client per PID can create a window.
|
||||
HashMap<int, struct godot_embedded_client *> mapped_clients;
|
||||
|
||||
OS::ProcessID focused_pid = -1;
|
||||
};
|
||||
|
||||
struct EmbeddedClientState {
|
||||
struct godot_embedding_compositor *embedding_compositor = nullptr;
|
||||
|
||||
uint32_t pid = 0;
|
||||
bool window_mapped = false;
|
||||
};
|
||||
|
||||
private:
|
||||
struct ThreadData {
|
||||
SafeFlag thread_done;
|
||||
@@ -604,6 +631,10 @@ private:
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
WaylandEmbedder embedder;
|
||||
#endif
|
||||
|
||||
#ifdef LIBDECOR_ENABLED
|
||||
struct libdecor *libdecor_context = nullptr;
|
||||
#endif // LIBDECOR_ENABLED
|
||||
@@ -742,6 +773,13 @@ private:
|
||||
|
||||
static void _xdg_activation_token_on_done(void *data, struct xdg_activation_token_v1 *xdg_activation_token, const char *token);
|
||||
|
||||
static void _godot_embedding_compositor_on_client(void *data, struct godot_embedding_compositor *godot_embedding_compositor, struct godot_embedded_client *godot_embedded_client, int32_t pid);
|
||||
|
||||
static void _godot_embedded_client_on_disconnected(void *data, struct godot_embedded_client *godot_embedded_client);
|
||||
static void _godot_embedded_client_on_window_embedded(void *data, struct godot_embedded_client *godot_embedded_client);
|
||||
static void _godot_embedded_client_on_window_focus_in(void *data, struct godot_embedded_client *godot_embedded_client);
|
||||
static void _godot_embedded_client_on_window_focus_out(void *data, struct godot_embedded_client *godot_embedded_client);
|
||||
|
||||
// Core Wayland event listeners.
|
||||
static constexpr struct wl_registry_listener wl_registry_listener = {
|
||||
.global = _wl_registry_on_global,
|
||||
@@ -929,6 +967,18 @@ private:
|
||||
.done = _xdg_activation_token_on_done,
|
||||
};
|
||||
|
||||
// Godot interfaces.
|
||||
static constexpr struct godot_embedding_compositor_listener godot_embedding_compositor_listener = {
|
||||
.client = _godot_embedding_compositor_on_client,
|
||||
};
|
||||
|
||||
static constexpr struct godot_embedded_client_listener godot_embedded_client_listener = {
|
||||
.disconnected = _godot_embedded_client_on_disconnected,
|
||||
.window_embedded = _godot_embedded_client_on_window_embedded,
|
||||
.window_focus_in = _godot_embedded_client_on_window_focus_in,
|
||||
.window_focus_out = _godot_embedded_client_on_window_focus_out,
|
||||
};
|
||||
|
||||
#ifdef LIBDECOR_ENABLED
|
||||
// libdecor event handlers.
|
||||
static void libdecor_on_error(struct libdecor *context, enum libdecor_error error, const char *message);
|
||||
@@ -1009,6 +1059,8 @@ public:
|
||||
|
||||
static OfferState *wp_primary_selection_offer_get_offer_state(struct zwp_primary_selection_offer_v1 *p_offer);
|
||||
|
||||
static EmbeddingCompositorState *godot_embedding_compositor_get_state(struct godot_embedding_compositor *p_compositor);
|
||||
|
||||
void seat_state_unlock_pointer(SeatState *p_ss);
|
||||
void seat_state_lock_pointer(SeatState *p_ss);
|
||||
void seat_state_set_hint(SeatState *p_ss, int p_x, int p_y);
|
||||
@@ -1116,6 +1168,10 @@ public:
|
||||
bool window_is_suspended(DisplayServer::WindowID p_window_id) const;
|
||||
bool is_suspended() const;
|
||||
|
||||
struct godot_embedding_compositor *get_embedding_compositor();
|
||||
|
||||
OS::ProcessID embedded_compositor_get_focused_pid();
|
||||
|
||||
Error init();
|
||||
void destroy();
|
||||
};
|
||||
|
||||
4
thirdparty/README.md
vendored
4
thirdparty/README.md
vendored
@@ -1192,6 +1192,10 @@ Files extracted from upstream source:
|
||||
- `unstable/xdg-foreign/xdg-foreign-unstable-v1.xml`
|
||||
- `COPYING`
|
||||
|
||||
The following files are extracted from thirdparty sources:
|
||||
|
||||
- `mesa/wayland-drm.xml`: https://gitlab.freedesktop.org/mesa/mesa/-/blob/mesa-25.3.0/src/egl/wayland/wayland-drm/wayland-drm.xml
|
||||
|
||||
|
||||
## wslay
|
||||
|
||||
|
||||
189
thirdparty/wayland-protocols/mesa/wayland-drm.xml
vendored
Normal file
189
thirdparty/wayland-protocols/mesa/wayland-drm.xml
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="drm">
|
||||
|
||||
<copyright>
|
||||
Copyright © 2008-2011 Kristian Høgsberg
|
||||
Copyright © 2010-2011 Intel Corporation
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that\n the above copyright notice appear in
|
||||
all copies and that both that copyright notice and this permission
|
||||
notice appear in supporting documentation, and that the name of
|
||||
the copyright holders not be used in advertising or publicity
|
||||
pertaining to distribution of the software without specific,
|
||||
written prior permission. The copyright holders make no
|
||||
representations about the suitability of this software for any
|
||||
purpose. It is provided "as is" without express or implied
|
||||
warranty.
|
||||
|
||||
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<!-- drm support. This object is created by the server and published
|
||||
using the display's global event. -->
|
||||
<interface name="wl_drm" version="2">
|
||||
<enum name="error">
|
||||
<entry name="authenticate_fail" value="0"/>
|
||||
<entry name="invalid_format" value="1"/>
|
||||
<entry name="invalid_name" value="2"/>
|
||||
</enum>
|
||||
|
||||
<enum name="format">
|
||||
<!-- The drm format codes match the #defines in drm_fourcc.h.
|
||||
The formats actually supported by the compositor will be
|
||||
reported by the format event. New codes must not be added,
|
||||
unless directly taken from drm_fourcc.h. -->
|
||||
<entry name="c8" value="0x20203843"/>
|
||||
<entry name="rgb332" value="0x38424752"/>
|
||||
<entry name="bgr233" value="0x38524742"/>
|
||||
<entry name="xrgb4444" value="0x32315258"/>
|
||||
<entry name="xbgr4444" value="0x32314258"/>
|
||||
<entry name="rgbx4444" value="0x32315852"/>
|
||||
<entry name="bgrx4444" value="0x32315842"/>
|
||||
<entry name="argb4444" value="0x32315241"/>
|
||||
<entry name="abgr4444" value="0x32314241"/>
|
||||
<entry name="rgba4444" value="0x32314152"/>
|
||||
<entry name="bgra4444" value="0x32314142"/>
|
||||
<entry name="xrgb1555" value="0x35315258"/>
|
||||
<entry name="xbgr1555" value="0x35314258"/>
|
||||
<entry name="rgbx5551" value="0x35315852"/>
|
||||
<entry name="bgrx5551" value="0x35315842"/>
|
||||
<entry name="argb1555" value="0x35315241"/>
|
||||
<entry name="abgr1555" value="0x35314241"/>
|
||||
<entry name="rgba5551" value="0x35314152"/>
|
||||
<entry name="bgra5551" value="0x35314142"/>
|
||||
<entry name="rgb565" value="0x36314752"/>
|
||||
<entry name="bgr565" value="0x36314742"/>
|
||||
<entry name="rgb888" value="0x34324752"/>
|
||||
<entry name="bgr888" value="0x34324742"/>
|
||||
<entry name="xrgb8888" value="0x34325258"/>
|
||||
<entry name="xbgr8888" value="0x34324258"/>
|
||||
<entry name="rgbx8888" value="0x34325852"/>
|
||||
<entry name="bgrx8888" value="0x34325842"/>
|
||||
<entry name="argb8888" value="0x34325241"/>
|
||||
<entry name="abgr8888" value="0x34324241"/>
|
||||
<entry name="rgba8888" value="0x34324152"/>
|
||||
<entry name="bgra8888" value="0x34324142"/>
|
||||
<entry name="xrgb2101010" value="0x30335258"/>
|
||||
<entry name="xbgr2101010" value="0x30334258"/>
|
||||
<entry name="rgbx1010102" value="0x30335852"/>
|
||||
<entry name="bgrx1010102" value="0x30335842"/>
|
||||
<entry name="argb2101010" value="0x30335241"/>
|
||||
<entry name="abgr2101010" value="0x30334241"/>
|
||||
<entry name="rgba1010102" value="0x30334152"/>
|
||||
<entry name="bgra1010102" value="0x30334142"/>
|
||||
<entry name="yuyv" value="0x56595559"/>
|
||||
<entry name="yvyu" value="0x55595659"/>
|
||||
<entry name="uyvy" value="0x59565955"/>
|
||||
<entry name="vyuy" value="0x59555956"/>
|
||||
<entry name="ayuv" value="0x56555941"/>
|
||||
<entry name="xyuv8888" value="0x56555958"/>
|
||||
<entry name="nv12" value="0x3231564e"/>
|
||||
<entry name="nv21" value="0x3132564e"/>
|
||||
<entry name="nv16" value="0x3631564e"/>
|
||||
<entry name="nv61" value="0x3136564e"/>
|
||||
<entry name="yuv410" value="0x39565559"/>
|
||||
<entry name="yvu410" value="0x39555659"/>
|
||||
<entry name="yuv411" value="0x31315559"/>
|
||||
<entry name="yvu411" value="0x31315659"/>
|
||||
<entry name="yuv420" value="0x32315559"/>
|
||||
<entry name="yvu420" value="0x32315659"/>
|
||||
<entry name="yuv422" value="0x36315559"/>
|
||||
<entry name="yvu422" value="0x36315659"/>
|
||||
<entry name="yuv444" value="0x34325559"/>
|
||||
<entry name="yvu444" value="0x34325659"/>
|
||||
<entry name="abgr16f" value="0x48344241"/>
|
||||
<entry name="xbgr16f" value="0x48344258"/>
|
||||
</enum>
|
||||
|
||||
<!-- Call this request with the magic received from drmGetMagic().
|
||||
It will be passed on to the drmAuthMagic() or
|
||||
DRIAuthConnection() call. This authentication must be
|
||||
completed before create_buffer could be used. -->
|
||||
<request name="authenticate">
|
||||
<arg name="id" type="uint"/>
|
||||
</request>
|
||||
|
||||
<!-- Create a wayland buffer for the named DRM buffer. The DRM
|
||||
surface must have a name using the flink ioctl -->
|
||||
<request name="create_buffer">
|
||||
<arg name="id" type="new_id" interface="wl_buffer"/>
|
||||
<arg name="name" type="uint"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
<arg name="stride" type="uint"/>
|
||||
<arg name="format" type="uint"/>
|
||||
</request>
|
||||
|
||||
<!-- Create a wayland buffer for the named DRM buffer. The DRM
|
||||
surface must have a name using the flink ioctl -->
|
||||
<request name="create_planar_buffer">
|
||||
<arg name="id" type="new_id" interface="wl_buffer"/>
|
||||
<arg name="name" type="uint"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
<arg name="format" type="uint"/>
|
||||
<arg name="offset0" type="int"/>
|
||||
<arg name="stride0" type="int"/>
|
||||
<arg name="offset1" type="int"/>
|
||||
<arg name="stride1" type="int"/>
|
||||
<arg name="offset2" type="int"/>
|
||||
<arg name="stride2" type="int"/>
|
||||
</request>
|
||||
|
||||
<!-- Notification of the path of the drm device which is used by
|
||||
the server. The client should use this device for creating
|
||||
local buffers. Only buffers created from this device should
|
||||
be be passed to the server using this drm object's
|
||||
create_buffer request. -->
|
||||
<event name="device">
|
||||
<arg name="name" type="string"/>
|
||||
</event>
|
||||
|
||||
<event name="format">
|
||||
<arg name="format" type="uint"/>
|
||||
</event>
|
||||
|
||||
<!-- Raised if the authenticate request succeeded -->
|
||||
<event name="authenticated"/>
|
||||
|
||||
<enum name="capability" since="2">
|
||||
<description summary="wl_drm capability bitmask">
|
||||
Bitmask of capabilities.
|
||||
</description>
|
||||
<entry name="prime" value="1" summary="wl_drm prime available"/>
|
||||
</enum>
|
||||
|
||||
<event name="capabilities">
|
||||
<arg name="value" type="uint"/>
|
||||
</event>
|
||||
|
||||
<!-- Version 2 additions -->
|
||||
|
||||
<!-- Create a wayland buffer for the prime fd. Use for regular and planar
|
||||
buffers. Pass 0 for offset and stride for unused planes. -->
|
||||
<request name="create_prime_buffer" since="2">
|
||||
<arg name="id" type="new_id" interface="wl_buffer"/>
|
||||
<arg name="name" type="fd"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
<arg name="format" type="uint"/>
|
||||
<arg name="offset0" type="int"/>
|
||||
<arg name="stride0" type="int"/>
|
||||
<arg name="offset1" type="int"/>
|
||||
<arg name="stride1" type="int"/>
|
||||
<arg name="offset2" type="int"/>
|
||||
<arg name="stride2" type="int"/>
|
||||
</request>
|
||||
|
||||
</interface>
|
||||
|
||||
</protocol>
|
||||
5
thirdparty/wayland-protocols/stable/linux-dmabuf/README
vendored
Normal file
5
thirdparty/wayland-protocols/stable/linux-dmabuf/README
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
Linux DMA-BUF protocol
|
||||
|
||||
Maintainers:
|
||||
Pekka Paalanen <pekka.paalanen@collabora.co.uk>
|
||||
Daniel Stone <daniels@collabora.com>
|
||||
218
thirdparty/wayland-protocols/stable/linux-dmabuf/feedback.rst
vendored
Normal file
218
thirdparty/wayland-protocols/stable/linux-dmabuf/feedback.rst
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
.. Copyright 2021 Simon Ser
|
||||
|
||||
.. contents::
|
||||
|
||||
|
||||
linux-dmabuf feedback introduction
|
||||
==================================
|
||||
|
||||
linux-dmabuf feedback allows compositors and clients to negotiate optimal buffer
|
||||
allocation parameters. This document will assume that the compositor is using a
|
||||
rendering API such as OpenGL or Vulkan and KMS as the presentation API: even if
|
||||
linux-dmabuf feedback isn't restricted to this use-case, it's the most common.
|
||||
|
||||
linux-dmabuf feedback introduces the following concepts:
|
||||
|
||||
1. A main device. This is the render device that the compositor is using to
|
||||
perform composition. Compositors should always be able to display a buffer
|
||||
submitted by a client, so this device can be used as a fallback in case none
|
||||
of the more optimized code-paths work. Clients should allocate buffers such
|
||||
that they can be imported and textured from the main device.
|
||||
|
||||
2. One or more tranches. Each tranche consists of a target device, allocation
|
||||
flags and a set of format/modifier pairs. A tranche can be seen as a set of
|
||||
formats/modifier pairs that are compatible with the target device.
|
||||
|
||||
A tranche can have the ``scanout`` flag. It means that the target device is
|
||||
a KMS device, and that buffers allocated with one of the format/modifier
|
||||
pairs in the tranche are eligible for direct scanout.
|
||||
|
||||
Clients should use the tranches in order to allocate buffers with the most
|
||||
appropriate format/modifier and also to avoid allocating in private device
|
||||
memory when cross-device operations are going to happen.
|
||||
|
||||
linux-dmabuf feedback implementation notes
|
||||
==========================================
|
||||
|
||||
This section contains recommendations for client and compositor implementations.
|
||||
|
||||
For clients
|
||||
-----------
|
||||
|
||||
Clients are expected to either pick a fixed DRM format beforehand, or
|
||||
perform the following steps repeatedly until they find a suitable format.
|
||||
|
||||
Basic clients may only support static buffer allocation on startup. These
|
||||
clients should do the following:
|
||||
|
||||
1. Send a ``get_default_feedback`` request to get global feedback.
|
||||
2. Select the device indicated by ``main_device`` for allocation.
|
||||
3. For each tranche:
|
||||
|
||||
1. If ``tranche_target_device`` doesn't match the allocation device, ignore
|
||||
the tranche.
|
||||
2. Accumulate allocation flags from ``tranche_flags``.
|
||||
3. Accumulate format/modifier pairs received via ``tranche_formats`` in a
|
||||
list.
|
||||
4. When the ``tranche_done`` event is received, try to allocate the buffer
|
||||
with the accumulated list of modifiers and allocation flags. If that
|
||||
fails, proceed with the next tranche. If that succeeds, stop the loop.
|
||||
|
||||
4. Destroy the feedback object.
|
||||
|
||||
Tranches are ordered by preference: the more optimized tranches come first. As
|
||||
such, clients should use the first tranche that happens to work.
|
||||
|
||||
Some clients may have already selected the device they want to use beforehand.
|
||||
These clients can ignore the ``main_device`` event, and ignore tranches whose
|
||||
``tranche_target_device`` doesn't match the selected device. Such clients need
|
||||
to be prepared for the ``wp_linux_buffer_params.create`` request to potentially
|
||||
fail.
|
||||
|
||||
If the client allocates a buffer without specifying explicit modifiers on a
|
||||
device different from the one indicated by ``main_device``, then the client
|
||||
must force a linear layout.
|
||||
|
||||
Some clients might support re-negotiating the buffer format/modifier on the
|
||||
fly. These clients should send a ``get_surface_feedback`` request and keep the
|
||||
feedback object alive after the initial allocation. Each time a new set of
|
||||
feedback parameters is received (ended by the ``done`` event), they should
|
||||
perform the same steps as basic clients described above. They should detect
|
||||
when the optimal allocation parameters didn't change (same
|
||||
format/modifier/flags) to avoid needlessly re-allocating their buffers.
|
||||
|
||||
Some clients might additionally support switching the device used for
|
||||
allocations on the fly. Such clients should send a ``get_surface_feedback``
|
||||
request. For each tranche, select the device indicated by
|
||||
``tranche_target_device`` for allocation. Accumulate allocation flags (received
|
||||
via ``tranche_flags``) and format/modifier pairs (received via
|
||||
``tranche_formats``) as usual. When the ``tranche_done`` event is received, try
|
||||
to allocate the buffer with the accumulated list of modifiers and the
|
||||
allocation flags. Try to import the resulting buffer by sending a
|
||||
``wp_linux_buffer_params.create`` request (this might fail). Repeat with each
|
||||
tranche until an allocation and import succeeds. Each time a new set of
|
||||
feedback parameters is received, they should perform these steps again. They
|
||||
should detect when the optimal allocation parameters didn't change (same
|
||||
device/format/modifier/flags) to avoid needlessly re-allocating their buffers.
|
||||
|
||||
For compositors
|
||||
---------------
|
||||
|
||||
Basic compositors may only support texturing the DMA-BUFs via a rendering API
|
||||
such as OpenGL or Vulkan. Such compositors can send a single tranche as a reply
|
||||
to both ``get_default_feedback`` and ``get_surface_feedback``. Set the
|
||||
``main_device`` to the rendering device. Send the tranche with
|
||||
``tranche_target_device`` set to the rendering device and all of the DRM
|
||||
format/modifier pairs supported by the rendering API. Do not set the
|
||||
``scanout`` flag in the ``tranche_flags`` event.
|
||||
|
||||
Some compositors may support direct scan-out for full-screen surfaces. These
|
||||
compositors can re-send the feedback parameters when a surface becomes
|
||||
full-screen or leaves full-screen mode if the client has used the
|
||||
``get_surface_feedback`` request. The non-full-screen feedback parameters are
|
||||
the same as basic compositors described above. The full-screen feedback
|
||||
parameters have two tranches: one with the format/modifier pairs supported by
|
||||
the KMS plane, with the ``scanout`` flag set in the ``tranche_flags`` event and
|
||||
with ``tranche_target_device`` set to the KMS scan-out device; the other with
|
||||
the rest of the format/modifier pairs (supported for texturing, but not for
|
||||
scan-out), without the ``scanout`` flag set in the ``tranche_flags`` event, and
|
||||
with the ``tranche_target_device`` set to the rendering device.
|
||||
|
||||
Some compositors may support direct scan-out for all surfaces. These
|
||||
compositors can send two tranches for surfaces that become candidates for
|
||||
direct scan-out, similarly to compositors supporting direct scan-out for
|
||||
fullscreen surfaces. When a surface stops being a candidate for direct
|
||||
scan-out, compositors should re-send the feedback parameters optimized for
|
||||
texturing only. The way candidates for direct scan-out are selected is
|
||||
compositor policy, a possible implementation is to select as many surfaces as
|
||||
there are available hardware planes, starting from surfaces closer to the eye.
|
||||
|
||||
Some compositors may support multiple devices at the same time. If the
|
||||
compositor supports rendering with a fixed device and direct scan-out on a
|
||||
secondary device, it may send a separate tranche for surfaces displayed on
|
||||
the secondary device that are candidates for direct scan-out. The
|
||||
``tranche_target_device`` for this tranche will be the secondary device and
|
||||
will not match the ``main_device``.
|
||||
|
||||
Some compositors may support switching their rendering device at runtime or
|
||||
changing their rendering device depending on the surface. When the rendering
|
||||
device changes for a surface, such compositors may re-send the feedback
|
||||
parameters with a different ``main_device``. However there is a risk that
|
||||
clients don't support switching their device at runtime and continue using the
|
||||
previous device. For this reason, compositors should always have a fallback
|
||||
rendering device that they initially send as ``main_device``, such that these
|
||||
clients use said fallback device.
|
||||
|
||||
Compositors should not change the ``main_device`` on-the-fly when explicit
|
||||
modifiers are not supported, because there's a risk of importing buffers
|
||||
with an implicit non-linear modifier as a linear buffer, resulting in
|
||||
misinterpreted buffer contents.
|
||||
|
||||
Compositors should not send feedback parameters if they don't have a fallback
|
||||
path. For instance, compositors shouldn't send a format/modifier supported for
|
||||
direct scan-out but not supported by the rendering API for texturing.
|
||||
|
||||
Compositors can decide to use multiple tranches to describe the allocation
|
||||
parameters optimized for texturing. For example, if there are formats which
|
||||
have a fast texturing path and formats which have a slower texturing path, the
|
||||
compositor can decide to expose two separate tranches.
|
||||
|
||||
Compositors can decide to use intermediate tranches to describe code-paths
|
||||
slower than direct scan-out but faster than texturing. For instance, a
|
||||
compositor could insert an intermediate tranche if it's possible to use a
|
||||
mem2mem device to convert buffers to be able to use scan-out.
|
||||
|
||||
``dev_t`` encoding
|
||||
==================
|
||||
|
||||
The protocol carries ``dev_t`` values on the wire using arrays. A compositor
|
||||
written in C can encode the values as follows:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct stat drm_node_stat;
|
||||
struct wl_array dev_array = {
|
||||
.size = sizeof(drm_node_stat.st_rdev),
|
||||
.data = &drm_node_stat.st_rdev,
|
||||
};
|
||||
|
||||
A client can decode the values as follows:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
dev_t dev;
|
||||
assert(dev_array->size == sizeof(dev));
|
||||
memcpy(&dev, dev_array->data, sizeof(dev));
|
||||
|
||||
Because two DRM nodes can refer to the same DRM device while having different
|
||||
``dev_t`` values, clients should use ``drmDevicesEqual`` to compare two
|
||||
devices.
|
||||
|
||||
``format_table`` encoding
|
||||
=========================
|
||||
|
||||
The ``format_table`` event carries a file descriptor containing a list of
|
||||
format + modifier pairs. The list is an array of pairs which can be accessed
|
||||
with this C structure definition:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct dmabuf_format_modifier {
|
||||
uint32_t format;
|
||||
uint32_t pad; /* unused */
|
||||
uint64_t modifier;
|
||||
};
|
||||
|
||||
Integration with other APIs
|
||||
===========================
|
||||
|
||||
- libdrm: ``drmGetDeviceFromDevId`` returns a ``drmDevice`` from a device ID.
|
||||
- EGL: the `EGL_EXT_device_drm_render_node`_ extension may be used to query the
|
||||
DRM device render node used by a given EGL display. When unavailable, the
|
||||
older `EGL_EXT_device_drm`_ extension may be used as a fallback.
|
||||
- Vulkan: the `VK_EXT_physical_device_drm`_ extension may be used to query the
|
||||
DRM device used by a given ``VkPhysicalDevice``.
|
||||
|
||||
.. _EGL_EXT_device_drm: https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_device_drm.txt
|
||||
.. _EGL_EXT_device_drm_render_node: https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_device_drm_render_node.txt
|
||||
.. _VK_EXT_physical_device_drm: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_physical_device_drm.html
|
||||
585
thirdparty/wayland-protocols/stable/linux-dmabuf/linux-dmabuf-v1.xml
vendored
Normal file
585
thirdparty/wayland-protocols/stable/linux-dmabuf/linux-dmabuf-v1.xml
vendored
Normal file
@@ -0,0 +1,585 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="linux_dmabuf_v1">
|
||||
|
||||
<copyright>
|
||||
Copyright © 2014, 2015 Collabora, Ltd.
|
||||
|
||||
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 (including the next
|
||||
paragraph) 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.
|
||||
</copyright>
|
||||
|
||||
<interface name="zwp_linux_dmabuf_v1" version="5">
|
||||
<description summary="factory for creating dmabuf-based wl_buffers">
|
||||
Following the interfaces from:
|
||||
https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_image_dma_buf_import.txt
|
||||
https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import_modifiers.txt
|
||||
and the Linux DRM sub-system's AddFb2 ioctl.
|
||||
|
||||
This interface offers ways to create generic dmabuf-based wl_buffers.
|
||||
|
||||
Clients can use the get_surface_feedback request to get dmabuf feedback
|
||||
for a particular surface. If the client wants to retrieve feedback not
|
||||
tied to a surface, they can use the get_default_feedback request.
|
||||
|
||||
The following are required from clients:
|
||||
|
||||
- Clients must ensure that either all data in the dma-buf is
|
||||
coherent for all subsequent read access or that coherency is
|
||||
correctly handled by the underlying kernel-side dma-buf
|
||||
implementation.
|
||||
|
||||
- Don't make any more attachments after sending the buffer to the
|
||||
compositor. Making more attachments later increases the risk of
|
||||
the compositor not being able to use (re-import) an existing
|
||||
dmabuf-based wl_buffer.
|
||||
|
||||
The underlying graphics stack must ensure the following:
|
||||
|
||||
- The dmabuf file descriptors relayed to the server will stay valid
|
||||
for the whole lifetime of the wl_buffer. This means the server may
|
||||
at any time use those fds to import the dmabuf into any kernel
|
||||
sub-system that might accept it.
|
||||
|
||||
However, when the underlying graphics stack fails to deliver the
|
||||
promise, because of e.g. a device hot-unplug which raises internal
|
||||
errors, after the wl_buffer has been successfully created the
|
||||
compositor must not raise protocol errors to the client when dmabuf
|
||||
import later fails.
|
||||
|
||||
To create a wl_buffer from one or more dmabufs, a client creates a
|
||||
zwp_linux_dmabuf_params_v1 object with a zwp_linux_dmabuf_v1.create_params
|
||||
request. All planes required by the intended format are added with
|
||||
the 'add' request. Finally, a 'create' or 'create_immed' request is
|
||||
issued, which has the following outcome depending on the import success.
|
||||
|
||||
The 'create' request,
|
||||
- on success, triggers a 'created' event which provides the final
|
||||
wl_buffer to the client.
|
||||
- on failure, triggers a 'failed' event to convey that the server
|
||||
cannot use the dmabufs received from the client.
|
||||
|
||||
For the 'create_immed' request,
|
||||
- on success, the server immediately imports the added dmabufs to
|
||||
create a wl_buffer. No event is sent from the server in this case.
|
||||
- on failure, the server can choose to either:
|
||||
- terminate the client by raising a fatal error.
|
||||
- mark the wl_buffer as failed, and send a 'failed' event to the
|
||||
client. If the client uses a failed wl_buffer as an argument to any
|
||||
request, the behaviour is compositor implementation-defined.
|
||||
|
||||
For all DRM formats and unless specified in another protocol extension,
|
||||
pre-multiplied alpha is used for pixel values.
|
||||
|
||||
Unless specified otherwise in another protocol extension, implicit
|
||||
synchronization is used. In other words, compositors and clients must
|
||||
wait and signal fences implicitly passed via the DMA-BUF's reservation
|
||||
mechanism.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="unbind the factory">
|
||||
Objects created through this interface, especially wl_buffers, will
|
||||
remain valid.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="create_params">
|
||||
<description summary="create a temporary object for buffer parameters">
|
||||
This temporary object is used to collect multiple dmabuf handles into
|
||||
a single batch to create a wl_buffer. It can only be used once and
|
||||
should be destroyed after a 'created' or 'failed' event has been
|
||||
received.
|
||||
</description>
|
||||
<arg name="params_id" type="new_id" interface="zwp_linux_buffer_params_v1"
|
||||
summary="the new temporary"/>
|
||||
</request>
|
||||
|
||||
<event name="format">
|
||||
<description summary="supported buffer format">
|
||||
This event advertises one buffer format that the server supports.
|
||||
All the supported formats are advertised once when the client
|
||||
binds to this interface. A roundtrip after binding guarantees
|
||||
that the client has received all supported formats.
|
||||
|
||||
For the definition of the format codes, see the
|
||||
zwp_linux_buffer_params_v1::create request.
|
||||
|
||||
Starting version 4, the format event is deprecated and must not be
|
||||
sent by compositors. Instead, use get_default_feedback or
|
||||
get_surface_feedback.
|
||||
</description>
|
||||
<arg name="format" type="uint" summary="DRM_FORMAT code"/>
|
||||
</event>
|
||||
|
||||
<event name="modifier" since="3">
|
||||
<description summary="supported buffer format modifier">
|
||||
This event advertises the formats that the server supports, along with
|
||||
the modifiers supported for each format. All the supported modifiers
|
||||
for all the supported formats are advertised once when the client
|
||||
binds to this interface. A roundtrip after binding guarantees that
|
||||
the client has received all supported format-modifier pairs.
|
||||
|
||||
For legacy support, DRM_FORMAT_MOD_INVALID (that is, modifier_hi ==
|
||||
0x00ffffff and modifier_lo == 0xffffffff) is allowed in this event.
|
||||
It indicates that the server can support the format with an implicit
|
||||
modifier. When a plane has DRM_FORMAT_MOD_INVALID as its modifier, it
|
||||
is as if no explicit modifier is specified. The effective modifier
|
||||
will be derived from the dmabuf.
|
||||
|
||||
A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for
|
||||
a given format supports both explicit modifiers and implicit modifiers.
|
||||
|
||||
For the definition of the format and modifier codes, see the
|
||||
zwp_linux_buffer_params_v1::create and zwp_linux_buffer_params_v1::add
|
||||
requests.
|
||||
|
||||
Starting version 4, the modifier event is deprecated and must not be
|
||||
sent by compositors. Instead, use get_default_feedback or
|
||||
get_surface_feedback.
|
||||
</description>
|
||||
<arg name="format" type="uint" summary="DRM_FORMAT code"/>
|
||||
<arg name="modifier_hi" type="uint"
|
||||
summary="high 32 bits of layout modifier"/>
|
||||
<arg name="modifier_lo" type="uint"
|
||||
summary="low 32 bits of layout modifier"/>
|
||||
</event>
|
||||
|
||||
<!-- Version 4 additions -->
|
||||
|
||||
<request name="get_default_feedback" since="4">
|
||||
<description summary="get default feedback">
|
||||
This request creates a new wp_linux_dmabuf_feedback object not bound
|
||||
to a particular surface. This object will deliver feedback about dmabuf
|
||||
parameters to use if the client doesn't support per-surface feedback
|
||||
(see get_surface_feedback).
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zwp_linux_dmabuf_feedback_v1"/>
|
||||
</request>
|
||||
|
||||
<request name="get_surface_feedback" since="4">
|
||||
<description summary="get feedback for a surface">
|
||||
This request creates a new wp_linux_dmabuf_feedback object for the
|
||||
specified wl_surface. This object will deliver feedback about dmabuf
|
||||
parameters to use for buffers attached to this surface.
|
||||
|
||||
If the surface is destroyed before the wp_linux_dmabuf_feedback object,
|
||||
the feedback object becomes inert.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zwp_linux_dmabuf_feedback_v1"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zwp_linux_buffer_params_v1" version="5">
|
||||
<description summary="parameters for creating a dmabuf-based wl_buffer">
|
||||
This temporary object is a collection of dmabufs and other
|
||||
parameters that together form a single logical buffer. The temporary
|
||||
object may eventually create one wl_buffer unless cancelled by
|
||||
destroying it before requesting 'create'.
|
||||
|
||||
Single-planar formats only require one dmabuf, however
|
||||
multi-planar formats may require more than one dmabuf. For all
|
||||
formats, an 'add' request must be called once per plane (even if the
|
||||
underlying dmabuf fd is identical).
|
||||
|
||||
You must use consecutive plane indices ('plane_idx' argument for 'add')
|
||||
from zero to the number of planes used by the drm_fourcc format code.
|
||||
All planes required by the format must be given exactly once, but can
|
||||
be given in any order. Each plane index can be set only once.
|
||||
</description>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="already_used" value="0"
|
||||
summary="the dmabuf_batch object has already been used to create a wl_buffer"/>
|
||||
<entry name="plane_idx" value="1"
|
||||
summary="plane index out of bounds"/>
|
||||
<entry name="plane_set" value="2"
|
||||
summary="the plane index was already set"/>
|
||||
<entry name="incomplete" value="3"
|
||||
summary="missing or too many planes to create a buffer"/>
|
||||
<entry name="invalid_format" value="4"
|
||||
summary="format not supported"/>
|
||||
<entry name="invalid_dimensions" value="5"
|
||||
summary="invalid width or height"/>
|
||||
<entry name="out_of_bounds" value="6"
|
||||
summary="offset + stride * height goes out of dmabuf bounds"/>
|
||||
<entry name="invalid_wl_buffer" value="7"
|
||||
summary="invalid wl_buffer resulted from importing dmabufs via
|
||||
the create_immed request on given buffer_params"/>
|
||||
</enum>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="delete this object, used or not">
|
||||
Cleans up the temporary data sent to the server for dmabuf-based
|
||||
wl_buffer creation.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="add">
|
||||
<description summary="add a dmabuf to the temporary set">
|
||||
This request adds one dmabuf to the set in this
|
||||
zwp_linux_buffer_params_v1.
|
||||
|
||||
The 64-bit unsigned value combined from modifier_hi and modifier_lo
|
||||
is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the
|
||||
fb modifier, which is defined in drm_mode.h of Linux UAPI.
|
||||
This is an opaque token. Drivers use this token to express tiling,
|
||||
compression, etc. driver-specific modifications to the base format
|
||||
defined by the DRM fourcc code.
|
||||
|
||||
Starting from version 4, the invalid_format protocol error is sent if
|
||||
the format + modifier pair was not advertised as supported.
|
||||
|
||||
Starting from version 5, the invalid_format protocol error is sent if
|
||||
all planes don't use the same modifier.
|
||||
|
||||
This request raises the PLANE_IDX error if plane_idx is too large.
|
||||
The error PLANE_SET is raised if attempting to set a plane that
|
||||
was already set.
|
||||
</description>
|
||||
<arg name="fd" type="fd" summary="dmabuf fd"/>
|
||||
<arg name="plane_idx" type="uint" summary="plane index"/>
|
||||
<arg name="offset" type="uint" summary="offset in bytes"/>
|
||||
<arg name="stride" type="uint" summary="stride in bytes"/>
|
||||
<arg name="modifier_hi" type="uint"
|
||||
summary="high 32 bits of layout modifier"/>
|
||||
<arg name="modifier_lo" type="uint"
|
||||
summary="low 32 bits of layout modifier"/>
|
||||
</request>
|
||||
|
||||
<enum name="flags" bitfield="true">
|
||||
<entry name="y_invert" value="1" summary="contents are y-inverted"/>
|
||||
<entry name="interlaced" value="2" summary="content is interlaced"/>
|
||||
<entry name="bottom_first" value="4" summary="bottom field first"/>
|
||||
</enum>
|
||||
|
||||
<request name="create">
|
||||
<description summary="create a wl_buffer from the given dmabufs">
|
||||
This asks for creation of a wl_buffer from the added dmabuf
|
||||
buffers. The wl_buffer is not created immediately but returned via
|
||||
the 'created' event if the dmabuf sharing succeeds. The sharing
|
||||
may fail at runtime for reasons a client cannot predict, in
|
||||
which case the 'failed' event is triggered.
|
||||
|
||||
The 'format' argument is a DRM_FORMAT code, as defined by the
|
||||
libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the
|
||||
authoritative source on how the format codes should work.
|
||||
|
||||
The 'flags' is a bitfield of the flags defined in enum "flags".
|
||||
'y_invert' means the that the image needs to be y-flipped.
|
||||
|
||||
Flag 'interlaced' means that the frame in the buffer is not
|
||||
progressive as usual, but interlaced. An interlaced buffer as
|
||||
supported here must always contain both top and bottom fields.
|
||||
The top field always begins on the first pixel row. The temporal
|
||||
ordering between the two fields is top field first, unless
|
||||
'bottom_first' is specified. It is undefined whether 'bottom_first'
|
||||
is ignored if 'interlaced' is not set.
|
||||
|
||||
This protocol does not convey any information about field rate,
|
||||
duration, or timing, other than the relative ordering between the
|
||||
two fields in one buffer. A compositor may have to estimate the
|
||||
intended field rate from the incoming buffer rate. It is undefined
|
||||
whether the time of receiving wl_surface.commit with a new buffer
|
||||
attached, applying the wl_surface state, wl_surface.frame callback
|
||||
trigger, presentation, or any other point in the compositor cycle
|
||||
is used to measure the frame or field times. There is no support
|
||||
for detecting missed or late frames/fields/buffers either, and
|
||||
there is no support whatsoever for cooperating with interlaced
|
||||
compositor output.
|
||||
|
||||
The composited image quality resulting from the use of interlaced
|
||||
buffers is explicitly undefined. A compositor may use elaborate
|
||||
hardware features or software to deinterlace and create progressive
|
||||
output frames from a sequence of interlaced input buffers, or it
|
||||
may produce substandard image quality. However, compositors that
|
||||
cannot guarantee reasonable image quality in all cases are recommended
|
||||
to just reject all interlaced buffers.
|
||||
|
||||
Any argument errors, including non-positive width or height,
|
||||
mismatch between the number of planes and the format, bad
|
||||
format, bad offset or stride, may be indicated by fatal protocol
|
||||
errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS,
|
||||
OUT_OF_BOUNDS.
|
||||
|
||||
Dmabuf import errors in the server that are not obvious client
|
||||
bugs are returned via the 'failed' event as non-fatal. This
|
||||
allows attempting dmabuf sharing and falling back in the client
|
||||
if it fails.
|
||||
|
||||
This request can be sent only once in the object's lifetime, after
|
||||
which the only legal request is destroy. This object should be
|
||||
destroyed after issuing a 'create' request. Attempting to use this
|
||||
object after issuing 'create' raises ALREADY_USED protocol error.
|
||||
|
||||
It is not mandatory to issue 'create'. If a client wants to
|
||||
cancel the buffer creation, it can just destroy this object.
|
||||
</description>
|
||||
<arg name="width" type="int" summary="base plane width in pixels"/>
|
||||
<arg name="height" type="int" summary="base plane height in pixels"/>
|
||||
<arg name="format" type="uint" summary="DRM_FORMAT code"/>
|
||||
<arg name="flags" type="uint" enum="flags" summary="see enum flags"/>
|
||||
</request>
|
||||
|
||||
<event name="created">
|
||||
<description summary="buffer creation succeeded">
|
||||
This event indicates that the attempted buffer creation was
|
||||
successful. It provides the new wl_buffer referencing the dmabuf(s).
|
||||
|
||||
Upon receiving this event, the client should destroy the
|
||||
zwp_linux_buffer_params_v1 object.
|
||||
</description>
|
||||
<arg name="buffer" type="new_id" interface="wl_buffer"
|
||||
summary="the newly created wl_buffer"/>
|
||||
</event>
|
||||
|
||||
<event name="failed">
|
||||
<description summary="buffer creation failed">
|
||||
This event indicates that the attempted buffer creation has
|
||||
failed. It usually means that one of the dmabuf constraints
|
||||
has not been fulfilled.
|
||||
|
||||
Upon receiving this event, the client should destroy the
|
||||
zwp_linux_buffer_params_v1 object.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<request name="create_immed" since="2">
|
||||
<description summary="immediately create a wl_buffer from the given
|
||||
dmabufs">
|
||||
This asks for immediate creation of a wl_buffer by importing the
|
||||
added dmabufs.
|
||||
|
||||
In case of import success, no event is sent from the server, and the
|
||||
wl_buffer is ready to be used by the client.
|
||||
|
||||
Upon import failure, either of the following may happen, as seen fit
|
||||
by the implementation:
|
||||
- the client is terminated with one of the following fatal protocol
|
||||
errors:
|
||||
- INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS,
|
||||
in case of argument errors such as mismatch between the number
|
||||
of planes and the format, bad format, non-positive width or
|
||||
height, or bad offset or stride.
|
||||
- INVALID_WL_BUFFER, in case the cause for failure is unknown or
|
||||
plaform specific.
|
||||
- the server creates an invalid wl_buffer, marks it as failed and
|
||||
sends a 'failed' event to the client. The result of using this
|
||||
invalid wl_buffer as an argument in any request by the client is
|
||||
defined by the compositor implementation.
|
||||
|
||||
This takes the same arguments as a 'create' request, and obeys the
|
||||
same restrictions.
|
||||
</description>
|
||||
<arg name="buffer_id" type="new_id" interface="wl_buffer"
|
||||
summary="id for the newly created wl_buffer"/>
|
||||
<arg name="width" type="int" summary="base plane width in pixels"/>
|
||||
<arg name="height" type="int" summary="base plane height in pixels"/>
|
||||
<arg name="format" type="uint" summary="DRM_FORMAT code"/>
|
||||
<arg name="flags" type="uint" enum="flags" summary="see enum flags"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zwp_linux_dmabuf_feedback_v1" version="5">
|
||||
<description summary="dmabuf feedback">
|
||||
This object advertises dmabuf parameters feedback. This includes the
|
||||
preferred devices and the supported formats/modifiers.
|
||||
|
||||
The parameters are sent once when this object is created and whenever they
|
||||
change. The done event is always sent once after all parameters have been
|
||||
sent. When a single parameter changes, all parameters are re-sent by the
|
||||
compositor.
|
||||
|
||||
Compositors can re-send the parameters when the current client buffer
|
||||
allocations are sub-optimal. Compositors should not re-send the
|
||||
parameters if re-allocating the buffers would not result in a more optimal
|
||||
configuration. In particular, compositors should avoid sending the exact
|
||||
same parameters multiple times in a row.
|
||||
|
||||
The tranche_target_device and tranche_formats events are grouped by
|
||||
tranches of preference. For each tranche, a tranche_target_device, one
|
||||
tranche_flags and one or more tranche_formats events are sent, followed
|
||||
by a tranche_done event finishing the list. The tranches are sent in
|
||||
descending order of preference. All formats and modifiers in the same
|
||||
tranche have the same preference.
|
||||
|
||||
To send parameters, the compositor sends one main_device event, tranches
|
||||
(each consisting of one tranche_target_device event, one tranche_flags
|
||||
event, tranche_formats events and then a tranche_done event), then one
|
||||
done event.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the feedback object">
|
||||
Using this request a client can tell the server that it is not going to
|
||||
use the wp_linux_dmabuf_feedback object anymore.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<event name="done">
|
||||
<description summary="all feedback has been sent">
|
||||
This event is sent after all parameters of a wp_linux_dmabuf_feedback
|
||||
object have been sent.
|
||||
|
||||
This allows changes to the wp_linux_dmabuf_feedback parameters to be
|
||||
seen as atomic, even if they happen via multiple events.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<event name="format_table">
|
||||
<description summary="format and modifier table">
|
||||
This event provides a file descriptor which can be memory-mapped to
|
||||
access the format and modifier table.
|
||||
|
||||
The table contains a tightly packed array of consecutive format +
|
||||
modifier pairs. Each pair is 16 bytes wide. It contains a format as a
|
||||
32-bit unsigned integer, followed by 4 bytes of unused padding, and a
|
||||
modifier as a 64-bit unsigned integer. The native endianness is used.
|
||||
|
||||
The client must map the file descriptor in read-only private mode.
|
||||
|
||||
Compositors are not allowed to mutate the table file contents once this
|
||||
event has been sent. Instead, compositors must create a new, separate
|
||||
table file and re-send feedback parameters. Compositors are allowed to
|
||||
store duplicate format + modifier pairs in the table.
|
||||
</description>
|
||||
<arg name="fd" type="fd" summary="table file descriptor"/>
|
||||
<arg name="size" type="uint" summary="table size, in bytes"/>
|
||||
</event>
|
||||
|
||||
<event name="main_device">
|
||||
<description summary="preferred main device">
|
||||
This event advertises the main device that the server prefers to use
|
||||
when direct scan-out to the target device isn't possible. The
|
||||
advertised main device may be different for each
|
||||
wp_linux_dmabuf_feedback object, and may change over time.
|
||||
|
||||
There is exactly one main device. The compositor must send at least
|
||||
one preference tranche with tranche_target_device equal to main_device.
|
||||
|
||||
Clients need to create buffers that the main device can import and
|
||||
read from, otherwise creating the dmabuf wl_buffer will fail (see the
|
||||
wp_linux_buffer_params.create and create_immed requests for details).
|
||||
The main device will also likely be kept active by the compositor,
|
||||
so clients can use it instead of waking up another device for power
|
||||
savings.
|
||||
|
||||
In general the device is a DRM node. The DRM node type (primary vs.
|
||||
render) is unspecified. Clients must not rely on the compositor sending
|
||||
a particular node type. Clients cannot check two devices for equality
|
||||
by comparing the dev_t value.
|
||||
|
||||
If explicit modifiers are not supported and the client performs buffer
|
||||
allocations on a different device than the main device, then the client
|
||||
must force the buffer to have a linear layout.
|
||||
</description>
|
||||
<arg name="device" type="array" summary="device dev_t value"/>
|
||||
</event>
|
||||
|
||||
<event name="tranche_done">
|
||||
<description summary="a preference tranche has been sent">
|
||||
This event splits tranche_target_device and tranche_formats events in
|
||||
preference tranches. It is sent after a set of tranche_target_device
|
||||
and tranche_formats events; it represents the end of a tranche. The
|
||||
next tranche will have a lower preference.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<event name="tranche_target_device">
|
||||
<description summary="target device">
|
||||
This event advertises the target device that the server prefers to use
|
||||
for a buffer created given this tranche. The advertised target device
|
||||
may be different for each preference tranche, and may change over time.
|
||||
|
||||
There is exactly one target device per tranche.
|
||||
|
||||
The target device may be a scan-out device, for example if the
|
||||
compositor prefers to directly scan-out a buffer created given this
|
||||
tranche. The target device may be a rendering device, for example if
|
||||
the compositor prefers to texture from said buffer.
|
||||
|
||||
The client can use this hint to allocate the buffer in a way that makes
|
||||
it accessible from the target device, ideally directly. The buffer must
|
||||
still be accessible from the main device, either through direct import
|
||||
or through a potentially more expensive fallback path. If the buffer
|
||||
can't be directly imported from the main device then clients must be
|
||||
prepared for the compositor changing the tranche priority or making
|
||||
wl_buffer creation fail (see the wp_linux_buffer_params.create and
|
||||
create_immed requests for details).
|
||||
|
||||
If the device is a DRM node, the DRM node type (primary vs. render) is
|
||||
unspecified. Clients must not rely on the compositor sending a
|
||||
particular node type. Clients cannot check two devices for equality by
|
||||
comparing the dev_t value.
|
||||
|
||||
This event is tied to a preference tranche, see the tranche_done event.
|
||||
</description>
|
||||
<arg name="device" type="array" summary="device dev_t value"/>
|
||||
</event>
|
||||
|
||||
<event name="tranche_formats">
|
||||
<description summary="supported buffer format modifier">
|
||||
This event advertises the format + modifier combinations that the
|
||||
compositor supports.
|
||||
|
||||
It carries an array of indices, each referring to a format + modifier
|
||||
pair in the last received format table (see the format_table event).
|
||||
Each index is a 16-bit unsigned integer in native endianness.
|
||||
|
||||
For legacy support, DRM_FORMAT_MOD_INVALID is an allowed modifier.
|
||||
It indicates that the server can support the format with an implicit
|
||||
modifier. When a buffer has DRM_FORMAT_MOD_INVALID as its modifier, it
|
||||
is as if no explicit modifier is specified. The effective modifier
|
||||
will be derived from the dmabuf.
|
||||
|
||||
A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for
|
||||
a given format supports both explicit modifiers and implicit modifiers.
|
||||
|
||||
Compositors must not send duplicate format + modifier pairs within the
|
||||
same tranche or across two different tranches with the same target
|
||||
device and flags.
|
||||
|
||||
This event is tied to a preference tranche, see the tranche_done event.
|
||||
|
||||
For the definition of the format and modifier codes, see the
|
||||
wp_linux_buffer_params.create request.
|
||||
</description>
|
||||
<arg name="indices" type="array" summary="array of 16-bit indexes"/>
|
||||
</event>
|
||||
|
||||
<enum name="tranche_flags" bitfield="true">
|
||||
<entry name="scanout" value="1" summary="direct scan-out tranche"/>
|
||||
</enum>
|
||||
|
||||
<event name="tranche_flags">
|
||||
<description summary="tranche flags">
|
||||
This event sets tranche-specific flags.
|
||||
|
||||
The scanout flag is a hint that direct scan-out may be attempted by the
|
||||
compositor on the target device if the client appropriately allocates a
|
||||
buffer. How to allocate a buffer that can be scanned out on the target
|
||||
device is implementation-defined.
|
||||
|
||||
This event is tied to a preference tranche, see the tranche_done event.
|
||||
</description>
|
||||
<arg name="flags" type="uint" enum="tranche_flags" summary="tranche flags"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
||||
4
thirdparty/wayland-protocols/staging/commit-timing/README
vendored
Normal file
4
thirdparty/wayland-protocols/staging/commit-timing/README
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
Commit Timing Protocol
|
||||
|
||||
Maintainers:
|
||||
Derek Foreman <derek.foreman@collabora.com> (@derekf)
|
||||
124
thirdparty/wayland-protocols/staging/commit-timing/commit-timing-v1.xml
vendored
Normal file
124
thirdparty/wayland-protocols/staging/commit-timing/commit-timing-v1.xml
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="commit_timing_v1">
|
||||
|
||||
<copyright>
|
||||
Copyright © 2023 Valve Corporation
|
||||
|
||||
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 (including the next
|
||||
paragraph) 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.
|
||||
</copyright>
|
||||
|
||||
<interface name="wp_commit_timing_manager_v1" version="1">
|
||||
<description summary="commit timing">
|
||||
When a compositor latches on to new content updates it will check for
|
||||
any number of requirements of the available content updates (such as
|
||||
fences of all buffers being signalled) to consider the update ready.
|
||||
|
||||
This protocol provides a method for adding a time constraint to surface
|
||||
content. This constraint indicates to the compositor that a content
|
||||
update should be presented as closely as possible to, but not before,
|
||||
a specified time.
|
||||
|
||||
This protocol does not change the Wayland property that content
|
||||
updates are applied in the order they are received, even when some
|
||||
content updates contain timestamps and others do not.
|
||||
|
||||
To provide timestamps, this global factory interface must be used to
|
||||
acquire a wp_commit_timing_v1 object for a surface, which may then be
|
||||
used to provide timestamp information for commits.
|
||||
|
||||
Warning! The protocol described in this file is currently in the testing
|
||||
phase. Backward compatible changes may be added together with the
|
||||
corresponding interface version bump. Backward incompatible changes can
|
||||
only be done by creating a new major version of the extension.
|
||||
</description>
|
||||
<enum name="error">
|
||||
<entry name="commit_timer_exists" value="0"
|
||||
summary="commit timer already exists for surface"/>
|
||||
</enum>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="unbind from the commit timing interface">
|
||||
Informs the server that the client will no longer be using
|
||||
this protocol object. Existing objects created by this object
|
||||
are not affected.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="get_timer">
|
||||
<description summary="request commit timer interface for surface">
|
||||
Establish a timing controller for a surface.
|
||||
|
||||
Only one commit timer can be created for a surface, or a
|
||||
commit_timer_exists protocol error will be generated.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="wp_commit_timer_v1"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="wp_commit_timer_v1" version="1">
|
||||
<description summary="Surface commit timer">
|
||||
An object to set a time constraint for a content update on a surface.
|
||||
</description>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="invalid_timestamp" value="0"
|
||||
summary="timestamp contains an invalid value"/>
|
||||
<entry name="timestamp_exists" value="1"
|
||||
summary="timestamp exists"/>
|
||||
<entry name="surface_destroyed" value="2"
|
||||
summary="the associated surface no longer exists"/>
|
||||
</enum>
|
||||
|
||||
<request name="set_timestamp">
|
||||
<description summary="Specify time the following commit takes effect">
|
||||
Provide a timing constraint for a surface content update.
|
||||
|
||||
A set_timestamp request may be made before a wl_surface.commit to
|
||||
tell the compositor that the content is intended to be presented
|
||||
as closely as possible to, but not before, the specified time.
|
||||
The time is in the domain of the compositor's presentation clock.
|
||||
|
||||
An invalid_timestamp error will be generated for invalid tv_nsec.
|
||||
|
||||
If a timestamp already exists on the surface, a timestamp_exists
|
||||
error is generated.
|
||||
|
||||
Requesting set_timestamp after the commit_timer object's surface is
|
||||
destroyed will generate a "surface_destroyed" error.
|
||||
</description>
|
||||
<arg name="tv_sec_hi" type="uint"
|
||||
summary="high 32 bits of the seconds part of target time"/>
|
||||
<arg name="tv_sec_lo" type="uint"
|
||||
summary="low 32 bits of the seconds part of target time"/>
|
||||
<arg name="tv_nsec" type="uint"
|
||||
summary="nanoseconds part of target time"/>
|
||||
</request>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="Destroy the timer">
|
||||
Informs the server that the client will no longer be using
|
||||
this protocol object.
|
||||
|
||||
Existing timing constraints are not affected by the destruction.
|
||||
</description>
|
||||
</request>
|
||||
</interface>
|
||||
</protocol>
|
||||
4
thirdparty/wayland-protocols/staging/fifo/README
vendored
Normal file
4
thirdparty/wayland-protocols/staging/fifo/README
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
Fifo Protocol
|
||||
|
||||
Maintainers:
|
||||
Derek Foreman <derek.foreman@collabora.com> (@derekf)
|
||||
143
thirdparty/wayland-protocols/staging/fifo/fifo-v1.xml
vendored
Normal file
143
thirdparty/wayland-protocols/staging/fifo/fifo-v1.xml
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="fifo_v1">
|
||||
<copyright>
|
||||
Copyright © 2023 Valve Corporation
|
||||
|
||||
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 (including the next
|
||||
paragraph) 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.
|
||||
</copyright>
|
||||
|
||||
<interface name="wp_fifo_manager_v1" version="1">
|
||||
<description summary="protocol for fifo constraints">
|
||||
When a Wayland compositor considers applying a content update,
|
||||
it must ensure all the update's readiness constraints (fences, etc)
|
||||
are met.
|
||||
|
||||
This protocol provides a way to use the completion of a display refresh
|
||||
cycle as an additional readiness constraint.
|
||||
|
||||
Warning! The protocol described in this file is currently in the testing
|
||||
phase. Backward compatible changes may be added together with the
|
||||
corresponding interface version bump. Backward incompatible changes can
|
||||
only be done by creating a new major version of the extension.
|
||||
</description>
|
||||
|
||||
<enum name="error">
|
||||
<description summary="fatal presentation error">
|
||||
These fatal protocol errors may be emitted in response to
|
||||
illegal requests.
|
||||
</description>
|
||||
<entry name="already_exists" value="0"
|
||||
summary="fifo manager already exists for surface"/>
|
||||
</enum>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="unbind from the manager interface">
|
||||
Informs the server that the client will no longer be using
|
||||
this protocol object. Existing objects created by this object
|
||||
are not affected.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="get_fifo">
|
||||
<description summary="request fifo interface for surface">
|
||||
Establish a fifo object for a surface that may be used to add
|
||||
display refresh constraints to content updates.
|
||||
|
||||
Only one such object may exist for a surface and attempting
|
||||
to create more than one will result in an already_exists
|
||||
protocol error. If a surface is acted on by multiple software
|
||||
components, general best practice is that only the component
|
||||
performing wl_surface.attach operations should use this protocol.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="wp_fifo_v1"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="wp_fifo_v1" version="1">
|
||||
<description summary="fifo interface">
|
||||
A fifo object for a surface that may be used to add
|
||||
display refresh constraints to content updates.
|
||||
</description>
|
||||
|
||||
<enum name="error">
|
||||
<description summary="fatal error">
|
||||
These fatal protocol errors may be emitted in response to
|
||||
illegal requests.
|
||||
</description>
|
||||
<entry name="surface_destroyed" value="0"
|
||||
summary="the associated surface no longer exists"/>
|
||||
</enum>
|
||||
|
||||
<request name="set_barrier">
|
||||
<description summary="sets the start point for a fifo constraint">
|
||||
When the content update containing the "set_barrier" is applied,
|
||||
it sets a "fifo_barrier" condition on the surface associated with
|
||||
the fifo object. The condition is cleared immediately after the
|
||||
following latching deadline for non-tearing presentation.
|
||||
|
||||
The compositor may clear the condition early if it must do so to
|
||||
ensure client forward progress assumptions.
|
||||
|
||||
To wait for this condition to clear, use the "wait_barrier" request.
|
||||
|
||||
"set_barrier" is double-buffered state, see wl_surface.commit.
|
||||
|
||||
Requesting set_barrier after the fifo object's surface is
|
||||
destroyed will generate a "surface_destroyed" error.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="wait_barrier">
|
||||
<description summary="adds a fifo constraint to a content update">
|
||||
Indicate that this content update is not ready while a
|
||||
"fifo_barrier" condition is present on the surface.
|
||||
|
||||
This means that when the content update containing "set_barrier"
|
||||
was made active at a latching deadline, it will be active for
|
||||
at least one refresh cycle. A content update which is allowed to
|
||||
tear might become active after a latching deadline if no content
|
||||
update became active at the deadline.
|
||||
|
||||
The constraint must be ignored if the surface is a subsurface in
|
||||
synchronized mode. If the surface is not being updated by the
|
||||
compositor (off-screen, occluded) the compositor may ignore the
|
||||
constraint. Clients must use an additional mechanism such as
|
||||
frame callbacks or timestamps to ensure throttling occurs under
|
||||
all conditions.
|
||||
|
||||
"wait_barrier" is double-buffered state, see wl_surface.commit.
|
||||
|
||||
Requesting "wait_barrier" after the fifo object's surface is
|
||||
destroyed will generate a "surface_destroyed" error.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the fifo interface">
|
||||
Informs the server that the client will no longer be using
|
||||
this protocol object.
|
||||
|
||||
Surface state changes previously made by this protocol are
|
||||
unaffected by this object's destruction.
|
||||
</description>
|
||||
</request>
|
||||
</interface>
|
||||
</protocol>
|
||||
4
thirdparty/wayland-protocols/staging/linux-drm-syncobj/README
vendored
Normal file
4
thirdparty/wayland-protocols/staging/linux-drm-syncobj/README
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
Linux DRM syncobj protocol
|
||||
|
||||
Maintainers:
|
||||
Simon Ser <contact@emersion.fr> (@emersion)
|
||||
261
thirdparty/wayland-protocols/staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml
vendored
Normal file
261
thirdparty/wayland-protocols/staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="linux_drm_syncobj_v1">
|
||||
<copyright>
|
||||
Copyright 2016 The Chromium Authors.
|
||||
Copyright 2017 Intel Corporation
|
||||
Copyright 2018 Collabora, Ltd
|
||||
Copyright 2021 Simon Ser
|
||||
|
||||
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 (including the next
|
||||
paragraph) 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.
|
||||
</copyright>
|
||||
|
||||
<description summary="protocol for providing explicit synchronization">
|
||||
This protocol allows clients to request explicit synchronization for
|
||||
buffers. It is tied to the Linux DRM synchronization object framework.
|
||||
|
||||
Synchronization refers to co-ordination of pipelined operations performed
|
||||
on buffers. Most GPU clients will schedule an asynchronous operation to
|
||||
render to the buffer, then immediately send the buffer to the compositor
|
||||
to be attached to a surface.
|
||||
|
||||
With implicit synchronization, ensuring that the rendering operation is
|
||||
complete before the compositor displays the buffer is an implementation
|
||||
detail handled by either the kernel or userspace graphics driver.
|
||||
|
||||
By contrast, with explicit synchronization, DRM synchronization object
|
||||
timeline points mark when the asynchronous operations are complete. When
|
||||
submitting a buffer, the client provides a timeline point which will be
|
||||
waited on before the compositor accesses the buffer, and another timeline
|
||||
point that the compositor will signal when it no longer needs to access the
|
||||
buffer contents for the purposes of the surface commit.
|
||||
|
||||
Linux DRM synchronization objects are documented at:
|
||||
https://dri.freedesktop.org/docs/drm/gpu/drm-mm.html#drm-sync-objects
|
||||
|
||||
Warning! The protocol described in this file is currently in the testing
|
||||
phase. Backward compatible changes may be added together with the
|
||||
corresponding interface version bump. Backward incompatible changes can
|
||||
only be done by creating a new major version of the extension.
|
||||
</description>
|
||||
|
||||
<interface name="wp_linux_drm_syncobj_manager_v1" version="1">
|
||||
<description summary="global for providing explicit synchronization">
|
||||
This global is a factory interface, allowing clients to request
|
||||
explicit synchronization for buffers on a per-surface basis.
|
||||
|
||||
See wp_linux_drm_syncobj_surface_v1 for more information.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy explicit synchronization factory object">
|
||||
Destroy this explicit synchronization factory object. Other objects
|
||||
shall not be affected by this request.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="surface_exists" value="0"
|
||||
summary="the surface already has a synchronization object associated"/>
|
||||
<entry name="invalid_timeline" value="1"
|
||||
summary="the timeline object could not be imported"/>
|
||||
</enum>
|
||||
|
||||
<request name="get_surface">
|
||||
<description summary="extend surface interface for explicit synchronization">
|
||||
Instantiate an interface extension for the given wl_surface to provide
|
||||
explicit synchronization.
|
||||
|
||||
If the given wl_surface already has an explicit synchronization object
|
||||
associated, the surface_exists protocol error is raised.
|
||||
|
||||
Graphics APIs, like EGL or Vulkan, that manage the buffer queue and
|
||||
commits of a wl_surface themselves, are likely to be using this
|
||||
extension internally. If a client is using such an API for a
|
||||
wl_surface, it should not directly use this extension on that surface,
|
||||
to avoid raising a surface_exists protocol error.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="wp_linux_drm_syncobj_surface_v1"
|
||||
summary="the new synchronization surface object id"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"
|
||||
summary="the surface"/>
|
||||
</request>
|
||||
|
||||
<request name="import_timeline">
|
||||
<description summary="import a DRM syncobj timeline">
|
||||
Import a DRM synchronization object timeline.
|
||||
|
||||
If the FD cannot be imported, the invalid_timeline error is raised.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="wp_linux_drm_syncobj_timeline_v1"/>
|
||||
<arg name="fd" type="fd" summary="drm_syncobj file descriptor"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="wp_linux_drm_syncobj_timeline_v1" version="1">
|
||||
<description summary="synchronization object timeline">
|
||||
This object represents an explicit synchronization object timeline
|
||||
imported by the client to the compositor.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the timeline">
|
||||
Destroy the synchronization object timeline. Other objects are not
|
||||
affected by this request, in particular timeline points set by
|
||||
set_acquire_point and set_release_point are not unset.
|
||||
</description>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="wp_linux_drm_syncobj_surface_v1" version="1">
|
||||
<description summary="per-surface explicit synchronization">
|
||||
This object is an add-on interface for wl_surface to enable explicit
|
||||
synchronization.
|
||||
|
||||
Each surface can be associated with only one object of this interface at
|
||||
any time.
|
||||
|
||||
Explicit synchronization is guaranteed to be supported for buffers
|
||||
created with any version of the linux-dmabuf protocol. Compositors are
|
||||
free to support explicit synchronization for additional buffer types.
|
||||
If at surface commit time the attached buffer does not support explicit
|
||||
synchronization, an unsupported_buffer error is raised.
|
||||
|
||||
As long as the wp_linux_drm_syncobj_surface_v1 object is alive, the
|
||||
compositor may ignore implicit synchronization for buffers attached and
|
||||
committed to the wl_surface. The delivery of wl_buffer.release events
|
||||
for buffers attached to the surface becomes undefined.
|
||||
|
||||
Clients must set both acquire and release points if and only if a
|
||||
non-null buffer is attached in the same surface commit. See the
|
||||
no_buffer, no_acquire_point and no_release_point protocol errors.
|
||||
|
||||
If at surface commit time the acquire and release DRM syncobj timelines
|
||||
are identical, the acquire point value must be strictly less than the
|
||||
release point value, or else the conflicting_points protocol error is
|
||||
raised.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the surface synchronization object">
|
||||
Destroy this surface synchronization object.
|
||||
|
||||
Any timeline point set by this object with set_acquire_point or
|
||||
set_release_point since the last commit may be discarded by the
|
||||
compositor. Any timeline point set by this object before the last
|
||||
commit will not be affected.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="no_surface" value="1"
|
||||
summary="the associated wl_surface was destroyed"/>
|
||||
<entry name="unsupported_buffer" value="2"
|
||||
summary="the buffer does not support explicit synchronization"/>
|
||||
<entry name="no_buffer" value="3" summary="no buffer was attached"/>
|
||||
<entry name="no_acquire_point" value="4"
|
||||
summary="no acquire timeline point was set"/>
|
||||
<entry name="no_release_point" value="5"
|
||||
summary="no release timeline point was set"/>
|
||||
<entry name="conflicting_points" value="6"
|
||||
summary="acquire and release timeline points are in conflict"/>
|
||||
</enum>
|
||||
|
||||
<request name="set_acquire_point">
|
||||
<description summary="set the acquire timeline point">
|
||||
Set the timeline point that must be signalled before the compositor may
|
||||
sample from the buffer attached with wl_surface.attach.
|
||||
|
||||
The 64-bit unsigned value combined from point_hi and point_lo is the
|
||||
point value.
|
||||
|
||||
The acquire point is double-buffered state, and will be applied on the
|
||||
next wl_surface.commit request for the associated surface. Thus, it
|
||||
applies only to the buffer that is attached to the surface at commit
|
||||
time.
|
||||
|
||||
If an acquire point has already been attached during the same commit
|
||||
cycle, the new point replaces the old one.
|
||||
|
||||
If the associated wl_surface was destroyed, a no_surface error is
|
||||
raised.
|
||||
|
||||
If at surface commit time there is a pending acquire timeline point set
|
||||
but no pending buffer attached, a no_buffer error is raised. If at
|
||||
surface commit time there is a pending buffer attached but no pending
|
||||
acquire timeline point set, the no_acquire_point protocol error is
|
||||
raised.
|
||||
</description>
|
||||
<arg name="timeline" type="object" interface="wp_linux_drm_syncobj_timeline_v1"/>
|
||||
<arg name="point_hi" type="uint" summary="high 32 bits of the point value"/>
|
||||
<arg name="point_lo" type="uint" summary="low 32 bits of the point value"/>
|
||||
</request>
|
||||
|
||||
<request name="set_release_point">
|
||||
<description summary="set the release timeline point">
|
||||
Set the timeline point that must be signalled by the compositor when it
|
||||
has finished its usage of the buffer attached with wl_surface.attach
|
||||
for the relevant commit.
|
||||
|
||||
Once the timeline point is signaled, and assuming the associated buffer
|
||||
is not pending release from other wl_surface.commit requests, no
|
||||
additional explicit or implicit synchronization with the compositor is
|
||||
required to safely re-use the buffer.
|
||||
|
||||
Note that clients cannot rely on the release point being always
|
||||
signaled after the acquire point: compositors may release buffers
|
||||
without ever reading from them. In addition, the compositor may use
|
||||
different presentation paths for different commits, which may have
|
||||
different release behavior. As a result, the compositor may signal the
|
||||
release points in a different order than the client committed them.
|
||||
|
||||
Because signaling a timeline point also signals every previous point,
|
||||
it is generally not safe to use the same timeline object for the
|
||||
release points of multiple buffers. The out-of-order signaling
|
||||
described above may lead to a release point being signaled before the
|
||||
compositor has finished reading. To avoid this, it is strongly
|
||||
recommended that each buffer should use a separate timeline for its
|
||||
release points.
|
||||
|
||||
The 64-bit unsigned value combined from point_hi and point_lo is the
|
||||
point value.
|
||||
|
||||
The release point is double-buffered state, and will be applied on the
|
||||
next wl_surface.commit request for the associated surface. Thus, it
|
||||
applies only to the buffer that is attached to the surface at commit
|
||||
time.
|
||||
|
||||
If a release point has already been attached during the same commit
|
||||
cycle, the new point replaces the old one.
|
||||
|
||||
If the associated wl_surface was destroyed, a no_surface error is
|
||||
raised.
|
||||
|
||||
If at surface commit time there is a pending release timeline point set
|
||||
but no pending buffer attached, a no_buffer error is raised. If at
|
||||
surface commit time there is a pending buffer attached but no pending
|
||||
release timeline point set, the no_release_point protocol error is
|
||||
raised.
|
||||
</description>
|
||||
<arg name="timeline" type="object" interface="wp_linux_drm_syncobj_timeline_v1"/>
|
||||
<arg name="point_hi" type="uint" summary="high 32 bits of the point value"/>
|
||||
<arg name="point_lo" type="uint" summary="low 32 bits of the point value"/>
|
||||
</request>
|
||||
</interface>
|
||||
</protocol>
|
||||
4
thirdparty/wayland-protocols/staging/tearing-control/README
vendored
Normal file
4
thirdparty/wayland-protocols/staging/tearing-control/README
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
Tearing control protocol
|
||||
|
||||
Maintainers:
|
||||
Xaver Hugl <xaver.hugl@gmail.com> (@Zamundaaa)
|
||||
123
thirdparty/wayland-protocols/staging/tearing-control/tearing-control-v1.xml
vendored
Normal file
123
thirdparty/wayland-protocols/staging/tearing-control/tearing-control-v1.xml
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="tearing_control_v1">
|
||||
<copyright>
|
||||
Copyright © 2021 Xaver Hugl
|
||||
|
||||
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 (including the next
|
||||
paragraph) 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.
|
||||
</copyright>
|
||||
|
||||
<interface name="wp_tearing_control_manager_v1" version="1">
|
||||
<description summary="protocol for tearing control">
|
||||
For some use cases like games or drawing tablets it can make sense to
|
||||
reduce latency by accepting tearing with the use of asynchronous page
|
||||
flips. This global is a factory interface, allowing clients to inform
|
||||
which type of presentation the content of their surfaces is suitable for.
|
||||
|
||||
Graphics APIs like EGL or Vulkan, that manage the buffer queue and commits
|
||||
of a wl_surface themselves, are likely to be using this extension
|
||||
internally. If a client is using such an API for a wl_surface, it should
|
||||
not directly use this extension on that surface, to avoid raising a
|
||||
tearing_control_exists protocol error.
|
||||
|
||||
Warning! The protocol described in this file is currently in the testing
|
||||
phase. Backward compatible changes may be added together with the
|
||||
corresponding interface version bump. Backward incompatible changes can
|
||||
only be done by creating a new major version of the extension.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy tearing control factory object">
|
||||
Destroy this tearing control factory object. Other objects, including
|
||||
wp_tearing_control_v1 objects created by this factory, are not affected
|
||||
by this request.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="tearing_control_exists" value="0"
|
||||
summary="the surface already has a tearing object associated"/>
|
||||
</enum>
|
||||
|
||||
<request name="get_tearing_control">
|
||||
<description summary="extend surface interface for tearing control">
|
||||
Instantiate an interface extension for the given wl_surface to request
|
||||
asynchronous page flips for presentation.
|
||||
|
||||
If the given wl_surface already has a wp_tearing_control_v1 object
|
||||
associated, the tearing_control_exists protocol error is raised.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="wp_tearing_control_v1"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="wp_tearing_control_v1" version="1">
|
||||
<description summary="per-surface tearing control interface">
|
||||
An additional interface to a wl_surface object, which allows the client
|
||||
to hint to the compositor if the content on the surface is suitable for
|
||||
presentation with tearing.
|
||||
The default presentation hint is vsync. See presentation_hint for more
|
||||
details.
|
||||
|
||||
If the associated wl_surface is destroyed, this object becomes inert and
|
||||
should be destroyed.
|
||||
</description>
|
||||
|
||||
<enum name="presentation_hint">
|
||||
<description summary="presentation hint values">
|
||||
This enum provides information for if submitted frames from the client
|
||||
may be presented with tearing.
|
||||
</description>
|
||||
<entry name="vsync" value="0">
|
||||
<description summary="tearing-free presentation">
|
||||
The content of this surface is meant to be synchronized to the
|
||||
vertical blanking period. This should not result in visible tearing
|
||||
and may result in a delay before a surface commit is presented.
|
||||
</description>
|
||||
</entry>
|
||||
<entry name="async" value="1">
|
||||
<description summary="asynchronous presentation">
|
||||
The content of this surface is meant to be presented with minimal
|
||||
latency and tearing is acceptable.
|
||||
</description>
|
||||
</entry>
|
||||
</enum>
|
||||
|
||||
<request name="set_presentation_hint">
|
||||
<description summary="set presentation hint">
|
||||
Set the presentation hint for the associated wl_surface. This state is
|
||||
double-buffered, see wl_surface.commit.
|
||||
|
||||
The compositor is free to dynamically respect or ignore this hint based
|
||||
on various conditions like hardware capabilities, surface state and
|
||||
user preferences.
|
||||
</description>
|
||||
<arg name="hint" type="uint" enum="presentation_hint"/>
|
||||
</request>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy tearing control object">
|
||||
Destroy this surface tearing object and revert the presentation hint to
|
||||
vsync. The change will be applied on the next wl_surface.commit.
|
||||
</description>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
||||
5
thirdparty/wayland-protocols/unstable/linux-explicit-synchronization/README
vendored
Normal file
5
thirdparty/wayland-protocols/unstable/linux-explicit-synchronization/README
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
Linux explicit synchronization (dma-fence) protocol
|
||||
|
||||
Maintainers:
|
||||
Daniel Stone <daniels@collabora.com>
|
||||
Alexandros Frantzis <alexandros.frantzis@collabora.com>
|
||||
@@ -0,0 +1,256 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="zwp_linux_explicit_synchronization_unstable_v1">
|
||||
|
||||
<copyright>
|
||||
Copyright 2016 The Chromium Authors.
|
||||
Copyright 2017 Intel Corporation
|
||||
Copyright 2018 Collabora, Ltd
|
||||
|
||||
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 (including the next
|
||||
paragraph) 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.
|
||||
</copyright>
|
||||
|
||||
<interface name="zwp_linux_explicit_synchronization_v1" version="2">
|
||||
<description summary="protocol for providing explicit synchronization">
|
||||
This global is a factory interface, allowing clients to request
|
||||
explicit synchronization for buffers on a per-surface basis.
|
||||
|
||||
See zwp_linux_surface_synchronization_v1 for more information.
|
||||
|
||||
This interface is derived from Chromium's
|
||||
zcr_linux_explicit_synchronization_v1.
|
||||
|
||||
Warning! The protocol described in this file is experimental and
|
||||
backward incompatible changes may be made. Backward compatible changes
|
||||
may be added together with the corresponding interface version bump.
|
||||
Backward incompatible changes are done by bumping the version number in
|
||||
the protocol and interface names and resetting the interface version.
|
||||
Once the protocol is to be declared stable, the 'z' prefix and the
|
||||
version number in the protocol and interface names are removed and the
|
||||
interface version number is reset.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy explicit synchronization factory object">
|
||||
Destroy this explicit synchronization factory object. Other objects,
|
||||
including zwp_linux_surface_synchronization_v1 objects created by this
|
||||
factory, shall not be affected by this request.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="synchronization_exists" value="0"
|
||||
summary="the surface already has a synchronization object associated"/>
|
||||
</enum>
|
||||
|
||||
<request name="get_synchronization">
|
||||
<description summary="extend surface interface for explicit synchronization">
|
||||
Instantiate an interface extension for the given wl_surface to provide
|
||||
explicit synchronization.
|
||||
|
||||
If the given wl_surface already has an explicit synchronization object
|
||||
associated, the synchronization_exists protocol error is raised.
|
||||
|
||||
Graphics APIs, like EGL or Vulkan, that manage the buffer queue and
|
||||
commits of a wl_surface themselves, are likely to be using this
|
||||
extension internally. If a client is using such an API for a
|
||||
wl_surface, it should not directly use this extension on that surface,
|
||||
to avoid raising a synchronization_exists protocol error.
|
||||
</description>
|
||||
|
||||
<arg name="id" type="new_id"
|
||||
interface="zwp_linux_surface_synchronization_v1"
|
||||
summary="the new synchronization interface id"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"
|
||||
summary="the surface"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zwp_linux_surface_synchronization_v1" version="2">
|
||||
<description summary="per-surface explicit synchronization support">
|
||||
This object implements per-surface explicit synchronization.
|
||||
|
||||
Synchronization refers to co-ordination of pipelined operations performed
|
||||
on buffers. Most GPU clients will schedule an asynchronous operation to
|
||||
render to the buffer, then immediately send the buffer to the compositor
|
||||
to be attached to a surface.
|
||||
|
||||
In implicit synchronization, ensuring that the rendering operation is
|
||||
complete before the compositor displays the buffer is an implementation
|
||||
detail handled by either the kernel or userspace graphics driver.
|
||||
|
||||
By contrast, in explicit synchronization, dma_fence objects mark when the
|
||||
asynchronous operations are complete. When submitting a buffer, the
|
||||
client provides an acquire fence which will be waited on before the
|
||||
compositor accesses the buffer. The Wayland server, through a
|
||||
zwp_linux_buffer_release_v1 object, will inform the client with an event
|
||||
which may be accompanied by a release fence, when the compositor will no
|
||||
longer access the buffer contents due to the specific commit that
|
||||
requested the release event.
|
||||
|
||||
Each surface can be associated with only one object of this interface at
|
||||
any time.
|
||||
|
||||
In version 1 of this interface, explicit synchronization is only
|
||||
guaranteed to be supported for buffers created with any version of the
|
||||
wp_linux_dmabuf buffer factory. Version 2 additionally guarantees
|
||||
explicit synchronization support for opaque EGL buffers, which is a type
|
||||
of platform specific buffers described in the EGL_WL_bind_wayland_display
|
||||
extension. Compositors are free to support explicit synchronization for
|
||||
additional buffer types.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy synchronization object">
|
||||
Destroy this explicit synchronization object.
|
||||
|
||||
Any fence set by this object with set_acquire_fence since the last
|
||||
commit will be discarded by the server. Any fences set by this object
|
||||
before the last commit are not affected.
|
||||
|
||||
zwp_linux_buffer_release_v1 objects created by this object are not
|
||||
affected by this request.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="invalid_fence" value="0"
|
||||
summary="the fence specified by the client could not be imported"/>
|
||||
<entry name="duplicate_fence" value="1"
|
||||
summary="multiple fences added for a single surface commit"/>
|
||||
<entry name="duplicate_release" value="2"
|
||||
summary="multiple releases added for a single surface commit"/>
|
||||
<entry name="no_surface" value="3"
|
||||
summary="the associated wl_surface was destroyed"/>
|
||||
<entry name="unsupported_buffer" value="4"
|
||||
summary="the buffer does not support explicit synchronization"/>
|
||||
<entry name="no_buffer" value="5"
|
||||
summary="no buffer was attached"/>
|
||||
</enum>
|
||||
|
||||
<request name="set_acquire_fence">
|
||||
<description summary="set the acquire fence">
|
||||
Set the acquire fence that must be signaled before the compositor
|
||||
may sample from the buffer attached with wl_surface.attach. The fence
|
||||
is a dma_fence kernel object.
|
||||
|
||||
The acquire fence is double-buffered state, and will be applied on the
|
||||
next wl_surface.commit request for the associated surface. Thus, it
|
||||
applies only to the buffer that is attached to the surface at commit
|
||||
time.
|
||||
|
||||
If the provided fd is not a valid dma_fence fd, then an INVALID_FENCE
|
||||
error is raised.
|
||||
|
||||
If a fence has already been attached during the same commit cycle, a
|
||||
DUPLICATE_FENCE error is raised.
|
||||
|
||||
If the associated wl_surface was destroyed, a NO_SURFACE error is
|
||||
raised.
|
||||
|
||||
If at surface commit time the attached buffer does not support explicit
|
||||
synchronization, an UNSUPPORTED_BUFFER error is raised.
|
||||
|
||||
If at surface commit time there is no buffer attached, a NO_BUFFER
|
||||
error is raised.
|
||||
</description>
|
||||
<arg name="fd" type="fd" summary="acquire fence fd"/>
|
||||
</request>
|
||||
|
||||
<request name="get_release">
|
||||
<description summary="release fence for last-attached buffer">
|
||||
Create a listener for the release of the buffer attached by the
|
||||
client with wl_surface.attach. See zwp_linux_buffer_release_v1
|
||||
documentation for more information.
|
||||
|
||||
The release object is double-buffered state, and will be associated
|
||||
with the buffer that is attached to the surface at wl_surface.commit
|
||||
time.
|
||||
|
||||
If a zwp_linux_buffer_release_v1 object has already been requested for
|
||||
the surface in the same commit cycle, a DUPLICATE_RELEASE error is
|
||||
raised.
|
||||
|
||||
If the associated wl_surface was destroyed, a NO_SURFACE error
|
||||
is raised.
|
||||
|
||||
If at surface commit time there is no buffer attached, a NO_BUFFER
|
||||
error is raised.
|
||||
</description>
|
||||
<arg name="release" type="new_id" interface="zwp_linux_buffer_release_v1"
|
||||
summary="new zwp_linux_buffer_release_v1 object"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zwp_linux_buffer_release_v1" version="1">
|
||||
<description summary="buffer release explicit synchronization">
|
||||
This object is instantiated in response to a
|
||||
zwp_linux_surface_synchronization_v1.get_release request.
|
||||
|
||||
It provides an alternative to wl_buffer.release events, providing a
|
||||
unique release from a single wl_surface.commit request. The release event
|
||||
also supports explicit synchronization, providing a fence FD for the
|
||||
client to synchronize against.
|
||||
|
||||
Exactly one event, either a fenced_release or an immediate_release, will
|
||||
be emitted for the wl_surface.commit request. The compositor can choose
|
||||
release by release which event it uses.
|
||||
|
||||
This event does not replace wl_buffer.release events; servers are still
|
||||
required to send those events.
|
||||
|
||||
Once a buffer release object has delivered a 'fenced_release' or an
|
||||
'immediate_release' event it is automatically destroyed.
|
||||
</description>
|
||||
|
||||
<event name="fenced_release" type="destructor">
|
||||
<description summary="release buffer with fence">
|
||||
Sent when the compositor has finalised its usage of the associated
|
||||
buffer for the relevant commit, providing a dma_fence which will be
|
||||
signaled when all operations by the compositor on that buffer for that
|
||||
commit have finished.
|
||||
|
||||
Once the fence has signaled, and assuming the associated buffer is not
|
||||
pending release from other wl_surface.commit requests, no additional
|
||||
explicit or implicit synchronization is required to safely reuse or
|
||||
destroy the buffer.
|
||||
|
||||
This event destroys the zwp_linux_buffer_release_v1 object.
|
||||
</description>
|
||||
<arg name="fence" type="fd" summary="fence for last operation on buffer"/>
|
||||
</event>
|
||||
|
||||
<event name="immediate_release" type="destructor">
|
||||
<description summary="release buffer immediately">
|
||||
Sent when the compositor has finalised its usage of the associated
|
||||
buffer for the relevant commit, and either performed no operations
|
||||
using it, or has a guarantee that all its operations on that buffer for
|
||||
that commit have finished.
|
||||
|
||||
Once this event is received, and assuming the associated buffer is not
|
||||
pending release from other wl_surface.commit requests, no additional
|
||||
explicit or implicit synchronization is required to safely reuse or
|
||||
destroy the buffer.
|
||||
|
||||
This event destroys the zwp_linux_buffer_release_v1 object.
|
||||
</description>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
||||
Reference in New Issue
Block a user