mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-02-11 04:28:19 -05:00
test tear
This commit is contained in:
parent
05e9d149c1
commit
e72b9f4429
6 changed files with 186 additions and 12 deletions
|
|
@ -19,6 +19,7 @@ wayland_xmls = [
|
|||
wl_protocol_dir + '/staging/ext-image-capture-source/ext-image-capture-source-v1.xml',
|
||||
wl_protocol_dir + '/staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml',
|
||||
wl_protocol_dir + '/staging/ext-workspace/ext-workspace-v1.xml',
|
||||
wl_protocol_dir + '/staging/tearing-control/tearing-control-v1.xml',
|
||||
'wlr-foreign-toplevel-management-unstable-v1.xml',
|
||||
'dwl-ipc-unstable-v2.xml',
|
||||
'wlr-layer-shell-unstable-v1.xml',
|
||||
|
|
|
|||
|
|
@ -153,6 +153,20 @@ static inline void client_get_geometry(Client *c, struct wlr_box *geom) {
|
|||
*geom = c->surface.xdg->geometry;
|
||||
}
|
||||
|
||||
static inline Client *get_client_from_surface(struct wlr_surface *surface) {
|
||||
if (!surface)
|
||||
return NULL;
|
||||
|
||||
// 从 surface 的 data 指针获取 scene tree
|
||||
struct wlr_scene_tree *scene_tree = surface->data;
|
||||
if (!scene_tree)
|
||||
return NULL;
|
||||
|
||||
// 从 scene tree 的 node data 获取 Client
|
||||
Client *c = scene_tree->node.data;
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline Client *client_get_parent(Client *c) {
|
||||
Client *p = NULL;
|
||||
#ifdef XWAYLAND
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ int xwayland_persistence = 1; /* xwayland persistence */
|
|||
int syncobj_enable = 0;
|
||||
int adaptive_sync = 0;
|
||||
double drag_refresh_interval = 30.0;
|
||||
int allow_tearing = TEARING_DISABLED;
|
||||
|
||||
/* keyboard */
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "dwl-ipc.h"
|
||||
#include "ext-workspace.h"
|
||||
#include "foreign-toplevel.h"
|
||||
#include "tearing.h"
|
||||
#include "text-input.h"
|
||||
106
src/ext-protocol/tearing.h
Normal file
106
src/ext-protocol/tearing.h
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#include <wlr/types/wlr_tearing_control_v1.h>
|
||||
|
||||
struct tearing_controller {
|
||||
struct wlr_tearing_control_v1 *tearing_control;
|
||||
struct wl_listener set_hint;
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
typedef struct SendFrameDoneData {
|
||||
struct timespec when;
|
||||
struct Monitor *mon;
|
||||
} SendFrameDoneData;
|
||||
|
||||
struct wlr_tearing_control_manager_v1 *tearing_control;
|
||||
struct wl_listener tearing_new_object;
|
||||
|
||||
static void handle_controller_set_hint(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct tearing_controller *controller =
|
||||
wl_container_of(listener, controller, set_hint);
|
||||
Client *c = get_client_from_surface(controller->tearing_control->surface);
|
||||
if (c) {
|
||||
/*
|
||||
* tearing_control->current is actually an enum:
|
||||
* WP_TEARING_CONTROL_V1_PRESENTATION_HINT_VSYNC = 0
|
||||
* WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC = 1
|
||||
*
|
||||
* Using it as a bool here allows us to not ship the XML.
|
||||
*/
|
||||
c->tearing_hint = controller->tearing_control->current;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_controller_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct tearing_controller *controller =
|
||||
wl_container_of(listener, controller, destroy);
|
||||
wl_list_remove(&controller->set_hint.link);
|
||||
wl_list_remove(&controller->destroy.link);
|
||||
free(controller);
|
||||
}
|
||||
|
||||
void handle_tearing_new_object(struct wl_listener *listener, void *data) {
|
||||
struct wlr_tearing_control_v1 *new_tearing_control = data;
|
||||
|
||||
enum wp_tearing_control_v1_presentation_hint hint =
|
||||
wlr_tearing_control_manager_v1_surface_hint_from_surface(
|
||||
tearing_control, new_tearing_control->surface);
|
||||
wlr_log(WLR_DEBUG, "New presentation hint %d received for surface %p", hint,
|
||||
new_tearing_control->surface);
|
||||
|
||||
struct tearing_controller *controller =
|
||||
ecalloc(1, sizeof(struct tearing_controller));
|
||||
controller->tearing_control = new_tearing_control;
|
||||
|
||||
controller->set_hint.notify = handle_controller_set_hint;
|
||||
wl_signal_add(&new_tearing_control->events.set_hint, &controller->set_hint);
|
||||
|
||||
controller->destroy.notify = handle_controller_destroy;
|
||||
wl_signal_add(&new_tearing_control->events.destroy, &controller->destroy);
|
||||
}
|
||||
|
||||
bool output_get_tearing_allowance(Monitor *m) {
|
||||
/* never allow tearing when disabled */
|
||||
if (!allow_tearing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Client *c = selmon->sel;
|
||||
|
||||
/* tearing is only allowed for the output with the active client */
|
||||
if (!c || c->mon != m) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* allow tearing for any window when requested or forced */
|
||||
if (allow_tearing == TEARING_ENABLED) {
|
||||
if (c->force_tearing == STATE_UNSPECIFIED) {
|
||||
return c->tearing_hint;
|
||||
} else {
|
||||
return c->force_tearing == STATE_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
/* remaining tearing options apply only to full-screen windows */
|
||||
if (!c->isfullscreen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (c->force_tearing == STATE_UNSPECIFIED) {
|
||||
/* honor the tearing hint or the fullscreen-force preference */
|
||||
return c->tearing_hint || allow_tearing == TEARING_FULLSCREEN_FORCED;
|
||||
}
|
||||
|
||||
/* honor tearing as requested by action */
|
||||
return c->force_tearing == STATE_ENABLED;
|
||||
}
|
||||
|
||||
void sendframedoneiterator(struct wlr_scene_buffer *buffer, int x, int y,
|
||||
void *user_data) {
|
||||
SendFrameDoneData *data = user_data;
|
||||
if (buffer->primary_output != data->mon->scene_output)
|
||||
return;
|
||||
|
||||
wlr_scene_buffer_send_frame_done(buffer, &data->when);
|
||||
}
|
||||
75
src/mango.c
75
src/mango.c
|
|
@ -164,6 +164,14 @@ enum { UP, DOWN, LEFT, RIGHT, UNDIR }; /* smartmovewin */
|
|||
enum { NONE, OPEN, MOVE, CLOSE, TAG };
|
||||
enum { UNFOLD, FOLD, INVALIDFOLD };
|
||||
enum { PREV, NEXT };
|
||||
enum { STATE_UNSPECIFIED = 0, STATE_ENABLED, STATE_DISABLED };
|
||||
|
||||
enum tearing_mode {
|
||||
TEARING_DISABLED = 0,
|
||||
TEARING_ENABLED,
|
||||
TEARING_FULLSCREEN,
|
||||
TEARING_FULLSCREEN_FORCED,
|
||||
};
|
||||
|
||||
typedef struct Pertag Pertag;
|
||||
typedef struct Monitor Monitor;
|
||||
|
|
@ -347,6 +355,8 @@ struct Client {
|
|||
bool ismaster;
|
||||
bool cursor_in_upper_half, cursor_in_left_half;
|
||||
bool isleftstack;
|
||||
bool tearing_hint;
|
||||
bool force_tearing;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -1940,6 +1950,7 @@ void cleanuplisteners(void) {
|
|||
wl_list_remove(&start_drag.link);
|
||||
wl_list_remove(&new_session_lock.link);
|
||||
wl_list_remove(&drm_lease_request.link);
|
||||
wl_list_remove(&tearing_new_object.link);
|
||||
#ifdef XWAYLAND
|
||||
wl_list_remove(&new_xwayland_surface.link);
|
||||
wl_list_remove(&xwayland_ready.link);
|
||||
|
|
@ -4078,10 +4089,27 @@ void rendermon(struct wl_listener *listener, void *data) {
|
|||
|
||||
struct timespec now;
|
||||
bool need_more_frames = false;
|
||||
bool skip_commit = false; // 新增:控制是否跳过提交
|
||||
|
||||
struct wlr_scene_output *scene_output = m->scene_output;
|
||||
SendFrameDoneData frame_done_data = {0};
|
||||
|
||||
m->wlr_output->frame_pending = false;
|
||||
|
||||
if (!wlr_scene_output_needs_frame(scene_output)) {
|
||||
goto skip;
|
||||
}
|
||||
|
||||
// // 初始化输出状态
|
||||
wlr_output_state_init(&pending);
|
||||
if (!wlr_scene_output_build_state(m->scene_output, &pending, NULL)) {
|
||||
wlr_output_state_finish(&pending);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
// 绘制层和淡出效果
|
||||
for (i = 0; i < LENGTH(m->layers); i++) {
|
||||
layer_list = &m->layers[i];
|
||||
// Draw frames for all layer
|
||||
wl_list_for_each_safe(l, tmpl, layer_list, link) {
|
||||
need_more_frames = layer_draw_frame(l) || need_more_frames;
|
||||
}
|
||||
|
|
@ -4095,24 +4123,43 @@ void rendermon(struct wl_listener *listener, void *data) {
|
|||
need_more_frames = layer_draw_fadeout_frame(l) || need_more_frames;
|
||||
}
|
||||
|
||||
// Draw frames for all clients
|
||||
// 绘制客户端并检查是否需要跳过提交
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
need_more_frames = client_draw_frame(c) || need_more_frames;
|
||||
if (!animations && c->configure_serial && !c->isfloating &&
|
||||
client_is_rendered_on_mon(c, m) && !client_is_stopped(c))
|
||||
goto skip;
|
||||
if (!animations && allow_tearing && c->configure_serial &&
|
||||
!c->isfloating && client_is_rendered_on_mon(c, m) &&
|
||||
!client_is_stopped(c)) {
|
||||
skip_commit = true; // 标记跳过提交,但不中断循环
|
||||
}
|
||||
}
|
||||
|
||||
wlr_scene_output_commit(m->scene_output, NULL);
|
||||
// 如果不需要跳过提交,才进行实际提交
|
||||
if (!skip_commit) {
|
||||
if (output_get_tearing_allowance(m)) {
|
||||
pending.tearing_page_flip = true;
|
||||
|
||||
if (!wlr_output_test_state(m->wlr_output, &pending)) {
|
||||
fprintf(stderr,
|
||||
"Output test failed on '%s', retrying without tearing "
|
||||
"page-flip\n",
|
||||
m->wlr_output->name);
|
||||
pending.tearing_page_flip = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wlr_output_commit_state(m->wlr_output, &pending))
|
||||
fprintf(stderr, "Page-flip failed on output %s",
|
||||
m->wlr_output->name);
|
||||
}
|
||||
|
||||
wlr_output_state_finish(&pending);
|
||||
|
||||
skip:
|
||||
|
||||
// Send frame done notification
|
||||
// 发送帧完成通知
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
wlr_scene_output_send_frame_done(m->scene_output, &now);
|
||||
|
||||
// // Clean up pending state
|
||||
wlr_output_state_finish(&pending);
|
||||
frame_done_data.mon = m;
|
||||
wlr_scene_output_for_each_buffer(m->scene_output, sendframedoneiterator,
|
||||
&frame_done_data);
|
||||
|
||||
if (need_more_frames) {
|
||||
wlr_output_schedule_frame(m->wlr_output);
|
||||
|
|
@ -4900,6 +4947,10 @@ void setup(void) {
|
|||
power_mgr = wlr_output_power_manager_v1_create(dpy);
|
||||
wl_signal_add(&power_mgr->events.set_mode, &output_power_mgr_set_mode);
|
||||
|
||||
tearing_control = wlr_tearing_control_manager_v1_create(dpy, 1);
|
||||
tearing_new_object.notify = handle_tearing_new_object;
|
||||
wl_signal_add(&tearing_control->events.new_object, &tearing_new_object);
|
||||
|
||||
/* Creates an output layout, which a wlroots utility for working with an
|
||||
* arrangement of screens in a physical layout. */
|
||||
output_layout = wlr_output_layout_create(dpy);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue