mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-11-02 03:45:58 +01:00
output: add damage tracking via buffer age
This commit is contained in:
parent
78c13ead16
commit
0365b587f0
21 changed files with 163 additions and 81 deletions
|
@ -183,12 +183,13 @@ void wlr_drm_resources_free(struct wlr_drm_backend *drm) {
|
||||||
free(drm->planes);
|
free(drm->planes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_drm_connector_make_current(struct wlr_output *output) {
|
static bool wlr_drm_connector_make_current(struct wlr_output *output,
|
||||||
|
int *buffer_age) {
|
||||||
struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output;
|
struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output;
|
||||||
wlr_drm_surface_make_current(&conn->crtc->primary->surf);
|
return wlr_drm_surface_make_current(&conn->crtc->primary->surf, buffer_age);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_drm_connector_swap_buffers(struct wlr_output *output) {
|
static bool wlr_drm_connector_swap_buffers(struct wlr_output *output) {
|
||||||
struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output;
|
struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output;
|
||||||
struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend;
|
struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend;
|
||||||
|
|
||||||
|
@ -203,7 +204,7 @@ static void wlr_drm_connector_swap_buffers(struct wlr_output *output) {
|
||||||
|
|
||||||
if (conn->pageflip_pending) {
|
if (conn->pageflip_pending) {
|
||||||
wlr_log(L_ERROR, "Skipping pageflip");
|
wlr_log(L_ERROR, "Skipping pageflip");
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, NULL)) {
|
if (drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, NULL)) {
|
||||||
|
@ -212,6 +213,8 @@ static void wlr_drm_connector_swap_buffers(struct wlr_output *output) {
|
||||||
wl_event_source_timer_update(conn->retry_pageflip,
|
wl_event_source_timer_update(conn->retry_pageflip,
|
||||||
1000000.0f / conn->output.current_mode->refresh);
|
1000000.0f / conn->output.current_mode->refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_drm_connector_set_gamma(struct wlr_output *output,
|
static void wlr_drm_connector_set_gamma(struct wlr_output *output,
|
||||||
|
@ -595,7 +598,7 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_drm_surface_make_current(&plane->surf);
|
wlr_drm_surface_make_current(&plane->surf, NULL);
|
||||||
|
|
||||||
wlr_texture_upload_pixels(plane->wlr_tex, WL_SHM_FORMAT_ARGB8888,
|
wlr_texture_upload_pixels(plane->wlr_tex, WL_SHM_FORMAT_ARGB8888,
|
||||||
stride, width, height, buf);
|
stride, width, height, buf);
|
||||||
|
|
|
@ -113,9 +113,9 @@ void wlr_drm_surface_finish(struct wlr_drm_surface *surf) {
|
||||||
memset(surf, 0, sizeof(*surf));
|
memset(surf, 0, sizeof(*surf));
|
||||||
}
|
}
|
||||||
|
|
||||||
void wlr_drm_surface_make_current(struct wlr_drm_surface *surf) {
|
bool wlr_drm_surface_make_current(struct wlr_drm_surface *surf,
|
||||||
eglMakeCurrent(surf->renderer->egl.display, surf->egl, surf->egl,
|
int *buffer_damage) {
|
||||||
surf->renderer->egl.context);
|
return wlr_egl_make_current(&surf->renderer->egl, surf->egl, buffer_damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct gbm_bo *wlr_drm_surface_swap_buffers(struct wlr_drm_surface *surf) {
|
struct gbm_bo *wlr_drm_surface_swap_buffers(struct wlr_drm_surface *surf) {
|
||||||
|
@ -123,7 +123,9 @@ struct gbm_bo *wlr_drm_surface_swap_buffers(struct wlr_drm_surface *surf) {
|
||||||
gbm_surface_release_buffer(surf->gbm, surf->front);
|
gbm_surface_release_buffer(surf->gbm, surf->front);
|
||||||
}
|
}
|
||||||
|
|
||||||
eglSwapBuffers(surf->renderer->egl.display, surf->egl);
|
if (!eglSwapBuffers(surf->renderer->egl.display, surf->egl)) {
|
||||||
|
wlr_log(L_ERROR, "eglSwapBuffers failed");
|
||||||
|
}
|
||||||
|
|
||||||
surf->front = surf->back;
|
surf->front = surf->back;
|
||||||
surf->back = gbm_surface_lock_front_buffer(surf->gbm);
|
surf->back = gbm_surface_lock_front_buffer(surf->gbm);
|
||||||
|
@ -135,7 +137,7 @@ struct gbm_bo *wlr_drm_surface_get_front(struct wlr_drm_surface *surf) {
|
||||||
return surf->front;
|
return surf->front;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_drm_surface_make_current(surf);
|
wlr_drm_surface_make_current(surf, NULL);
|
||||||
glViewport(0, 0, surf->width, surf->height);
|
glViewport(0, 0, surf->width, surf->height);
|
||||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
@ -207,8 +209,9 @@ static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, str
|
||||||
return tex->tex;
|
return tex->tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest, struct gbm_bo *src) {
|
struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest,
|
||||||
wlr_drm_surface_make_current(dest);
|
struct gbm_bo *src) {
|
||||||
|
wlr_drm_surface_make_current(dest, NULL);
|
||||||
|
|
||||||
struct wlr_texture *tex = get_tex_for_bo(dest->renderer, src);
|
struct wlr_texture *tex = get_tex_for_bo(dest->renderer, src);
|
||||||
|
|
||||||
|
|
|
@ -48,18 +48,15 @@ static void output_transform(struct wlr_output *wlr_output,
|
||||||
output->wlr_output.transform = transform;
|
output->wlr_output.transform = transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_make_current(struct wlr_output *wlr_output) {
|
static bool output_make_current(struct wlr_output *wlr_output, int *buffer_age) {
|
||||||
struct wlr_headless_output *output =
|
struct wlr_headless_output *output =
|
||||||
(struct wlr_headless_output *)wlr_output;
|
(struct wlr_headless_output *)wlr_output;
|
||||||
if (!eglMakeCurrent(output->backend->egl.display,
|
return wlr_egl_make_current(&output->backend->egl, output->egl_surface,
|
||||||
output->egl_surface, output->egl_surface,
|
buffer_age);
|
||||||
output->backend->egl.context)) {
|
|
||||||
wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_swap_buffers(struct wlr_output *wlr_output) {
|
static bool output_swap_buffers(struct wlr_output *wlr_output) {
|
||||||
// No-op
|
return true; // No-op
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_destroy(struct wlr_output *wlr_output) {
|
static void output_destroy(struct wlr_output *wlr_output) {
|
||||||
|
|
|
@ -38,22 +38,27 @@ static bool wlr_wl_output_set_custom_mode(struct wlr_output *_output,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_wl_output_make_current(struct wlr_output *_output) {
|
static bool wlr_wl_output_make_current(struct wlr_output *wlr_output,
|
||||||
struct wlr_wl_backend_output *output = (struct wlr_wl_backend_output *)_output;
|
int *buffer_age) {
|
||||||
if (!eglMakeCurrent(output->backend->egl.display,
|
struct wlr_wl_backend_output *output =
|
||||||
output->egl_surface, output->egl_surface,
|
(struct wlr_wl_backend_output *)wlr_output;
|
||||||
output->backend->egl.context)) {
|
return wlr_egl_make_current(&output->backend->egl, output->egl_surface,
|
||||||
wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error());
|
buffer_age);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_wl_output_swap_buffers(struct wlr_output *_output) {
|
static bool wlr_wl_output_swap_buffers(struct wlr_output *wlr_output) {
|
||||||
struct wlr_wl_backend_output *output = (struct wlr_wl_backend_output *)_output;
|
struct wlr_wl_backend_output *output =
|
||||||
|
(struct wlr_wl_backend_output *)wlr_output;
|
||||||
|
|
||||||
output->frame_callback = wl_surface_frame(output->surface);
|
output->frame_callback = wl_surface_frame(output->surface);
|
||||||
wl_callback_add_listener(output->frame_callback, &frame_listener, output);
|
wl_callback_add_listener(output->frame_callback, &frame_listener, output);
|
||||||
|
|
||||||
if (!eglSwapBuffers(output->backend->egl.display, output->egl_surface)) {
|
if (!eglSwapBuffers(output->backend->egl.display, output->egl_surface)) {
|
||||||
wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error());
|
wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_wl_output_transform(struct wlr_output *_output,
|
static void wlr_wl_output_transform(struct wlr_output *_output,
|
||||||
|
|
|
@ -379,28 +379,23 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
||||||
// output has been allocated on the stack, do not free it
|
// output has been allocated on the stack, do not free it
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_make_current(struct wlr_output *wlr_output) {
|
static bool output_make_current(struct wlr_output *wlr_output, int *buffer_age) {
|
||||||
struct wlr_x11_output *output = (struct wlr_x11_output *)wlr_output;
|
struct wlr_x11_output *output = (struct wlr_x11_output *)wlr_output;
|
||||||
struct wlr_x11_backend *x11 = output->x11;
|
struct wlr_x11_backend *x11 = output->x11;
|
||||||
|
|
||||||
if (!eglMakeCurrent(x11->egl.display, output->surf, output->surf, x11->egl.context)) {
|
return wlr_egl_make_current(&x11->egl, output->surf, buffer_age);
|
||||||
wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_swap_buffers(struct wlr_output *wlr_output) {
|
static bool output_swap_buffers(struct wlr_output *wlr_output) {
|
||||||
struct wlr_x11_output *output = (struct wlr_x11_output *)wlr_output;
|
struct wlr_x11_output *output = (struct wlr_x11_output *)wlr_output;
|
||||||
struct wlr_x11_backend *x11 = output->x11;
|
struct wlr_x11_backend *x11 = output->x11;
|
||||||
|
|
||||||
if (!eglSwapBuffers(x11->egl.display, output->surf)) {
|
if (!eglSwapBuffers(x11->egl.display, output->surf)) {
|
||||||
wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error());
|
wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Damage the whole output
|
return true;
|
||||||
// TODO: use the buffer age extension
|
|
||||||
pixman_region32_union_rect(&wlr_output->damage, &wlr_output->damage,
|
|
||||||
0, 0, wlr_output->width, wlr_output->height);
|
|
||||||
wlr_output_update_needs_swap(wlr_output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct wlr_output_impl output_impl = {
|
static struct wlr_output_impl output_impl = {
|
||||||
|
|
|
@ -56,7 +56,7 @@ static void handle_output_frame(struct output_state *output,
|
||||||
struct sample_state *sample = state->data;
|
struct sample_state *sample = state->data;
|
||||||
struct wlr_output *wlr_output = output->output;
|
struct wlr_output *wlr_output = output->output;
|
||||||
|
|
||||||
wlr_output_make_current(wlr_output);
|
wlr_output_make_current(wlr_output, NULL);
|
||||||
|
|
||||||
glClearColor(sample->clear_color[0], sample->clear_color[1],
|
glClearColor(sample->clear_color[0], sample->clear_color[1],
|
||||||
sample->clear_color[2], sample->clear_color[3]);
|
sample->clear_color[2], sample->clear_color[3]);
|
||||||
|
|
|
@ -100,7 +100,7 @@ static void handle_output_frame(struct output_state *output,
|
||||||
struct sample_state *sample = state->data;
|
struct sample_state *sample = state->data;
|
||||||
struct wlr_output *wlr_output = output->output;
|
struct wlr_output *wlr_output = output->output;
|
||||||
|
|
||||||
wlr_output_make_current(wlr_output);
|
wlr_output_make_current(wlr_output, NULL);
|
||||||
wlr_renderer_begin(sample->renderer, wlr_output);
|
wlr_renderer_begin(sample->renderer, wlr_output);
|
||||||
|
|
||||||
animate_cat(sample, output->output);
|
animate_cat(sample, output->output);
|
||||||
|
|
|
@ -85,7 +85,7 @@ static void handle_output_frame(struct output_state *output,
|
||||||
struct sample_state *sample = state->data;
|
struct sample_state *sample = state->data;
|
||||||
struct wlr_output *wlr_output = output->output;
|
struct wlr_output *wlr_output = output->output;
|
||||||
|
|
||||||
wlr_output_make_current(wlr_output);
|
wlr_output_make_current(wlr_output, NULL);
|
||||||
|
|
||||||
glClearColor(sample->clear_color[0], sample->clear_color[1],
|
glClearColor(sample->clear_color[0], sample->clear_color[1],
|
||||||
sample->clear_color[2], sample->clear_color[3]);
|
sample->clear_color[2], sample->clear_color[3]);
|
||||||
|
|
|
@ -42,7 +42,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts
|
||||||
int32_t width, height;
|
int32_t width, height;
|
||||||
wlr_output_effective_resolution(wlr_output, &width, &height);
|
wlr_output_effective_resolution(wlr_output, &width, &height);
|
||||||
|
|
||||||
wlr_output_make_current(wlr_output);
|
wlr_output_make_current(wlr_output, NULL);
|
||||||
wlr_renderer_begin(sample->renderer, wlr_output);
|
wlr_renderer_begin(sample->renderer, wlr_output);
|
||||||
|
|
||||||
float matrix[16];
|
float matrix[16];
|
||||||
|
|
|
@ -35,7 +35,7 @@ void handle_output_frame(struct output_state *output, struct timespec *ts) {
|
||||||
sample->dec = inc;
|
sample->dec = inc;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_output_make_current(output->output);
|
wlr_output_make_current(output->output, NULL);
|
||||||
|
|
||||||
glClearColor(sample->color[0], sample->color[1], sample->color[2], 1.0);
|
glClearColor(sample->color[0], sample->color[1], sample->color[2], 1.0);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
|
@ -42,7 +42,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts
|
||||||
int32_t width, height;
|
int32_t width, height;
|
||||||
wlr_output_effective_resolution(wlr_output, &width, &height);
|
wlr_output_effective_resolution(wlr_output, &width, &height);
|
||||||
|
|
||||||
wlr_output_make_current(wlr_output);
|
wlr_output_make_current(wlr_output, NULL);
|
||||||
wlr_renderer_begin(sample->renderer, wlr_output);
|
wlr_renderer_begin(sample->renderer, wlr_output);
|
||||||
|
|
||||||
float matrix[16], view[16];
|
float matrix[16], view[16];
|
||||||
|
|
|
@ -41,7 +41,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts
|
||||||
int32_t width, height;
|
int32_t width, height;
|
||||||
wlr_output_effective_resolution(wlr_output, &width, &height);
|
wlr_output_effective_resolution(wlr_output, &width, &height);
|
||||||
|
|
||||||
wlr_output_make_current(wlr_output);
|
wlr_output_make_current(wlr_output, NULL);
|
||||||
wlr_renderer_begin(sample->renderer, wlr_output);
|
wlr_renderer_begin(sample->renderer, wlr_output);
|
||||||
|
|
||||||
float matrix[16];
|
float matrix[16];
|
||||||
|
|
|
@ -45,7 +45,7 @@ bool wlr_drm_plane_surfaces_init(struct wlr_drm_plane *plane, struct wlr_drm_bac
|
||||||
int32_t width, uint32_t height, uint32_t format);
|
int32_t width, uint32_t height, uint32_t format);
|
||||||
|
|
||||||
void wlr_drm_surface_finish(struct wlr_drm_surface *surf);
|
void wlr_drm_surface_finish(struct wlr_drm_surface *surf);
|
||||||
void wlr_drm_surface_make_current(struct wlr_drm_surface *surf);
|
bool wlr_drm_surface_make_current(struct wlr_drm_surface *surf, int *buffer_age);
|
||||||
struct gbm_bo *wlr_drm_surface_swap_buffers(struct wlr_drm_surface *surf);
|
struct gbm_bo *wlr_drm_surface_swap_buffers(struct wlr_drm_surface *surf);
|
||||||
struct gbm_bo *wlr_drm_surface_get_front(struct wlr_drm_surface *surf);
|
struct gbm_bo *wlr_drm_surface_get_front(struct wlr_drm_surface *surf);
|
||||||
void wlr_drm_surface_post(struct wlr_drm_surface *surf);
|
void wlr_drm_surface_post(struct wlr_drm_surface *surf);
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
#include <wayland-server.h>
|
#include <wayland-server.h>
|
||||||
|
|
||||||
|
#define ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN 2
|
||||||
|
|
||||||
struct roots_desktop;
|
struct roots_desktop;
|
||||||
|
|
||||||
struct roots_output {
|
struct roots_output {
|
||||||
|
@ -15,9 +17,12 @@ struct roots_output {
|
||||||
struct roots_view *fullscreen_view;
|
struct roots_view *fullscreen_view;
|
||||||
|
|
||||||
struct timespec last_frame;
|
struct timespec last_frame;
|
||||||
pixman_region32_t damage, previous_damage;
|
pixman_region32_t damage;
|
||||||
bool frame_pending;
|
bool frame_pending;
|
||||||
|
|
||||||
|
pixman_region32_t previous_damage[ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN];
|
||||||
|
size_t previous_damage_idx;
|
||||||
|
|
||||||
struct wl_listener frame;
|
struct wl_listener frame;
|
||||||
struct wl_listener mode;
|
struct wl_listener mode;
|
||||||
struct wl_listener needs_swap;
|
struct wl_listener needs_swap;
|
||||||
|
|
|
@ -18,8 +18,8 @@ struct wlr_output_impl {
|
||||||
int32_t hotspot_x, int32_t hotspot_y, bool update_pixels);
|
int32_t hotspot_x, int32_t hotspot_y, bool update_pixels);
|
||||||
bool (*move_cursor)(struct wlr_output *output, int x, int y);
|
bool (*move_cursor)(struct wlr_output *output, int x, int y);
|
||||||
void (*destroy)(struct wlr_output *output);
|
void (*destroy)(struct wlr_output *output);
|
||||||
void (*make_current)(struct wlr_output *output);
|
bool (*make_current)(struct wlr_output *output, int *buffer_age);
|
||||||
void (*swap_buffers)(struct wlr_output *output);
|
bool (*swap_buffers)(struct wlr_output *output);
|
||||||
void (*set_gamma)(struct wlr_output *output,
|
void (*set_gamma)(struct wlr_output *output,
|
||||||
uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b);
|
uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b);
|
||||||
uint32_t (*get_gamma_size)(struct wlr_output *output);
|
uint32_t (*get_gamma_size)(struct wlr_output *output);
|
||||||
|
|
|
@ -11,8 +11,12 @@ struct wlr_egl {
|
||||||
EGLConfig config;
|
EGLConfig config;
|
||||||
EGLContext context;
|
EGLContext context;
|
||||||
|
|
||||||
const char *egl_exts;
|
const char *egl_exts_str;
|
||||||
const char *gl_exts;
|
const char *gl_exts_str;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool buffer_age;
|
||||||
|
} egl_exts;
|
||||||
|
|
||||||
struct wl_display *wl_display;
|
struct wl_display *wl_display;
|
||||||
};
|
};
|
||||||
|
@ -65,4 +69,10 @@ bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImageKHR image);
|
||||||
*/
|
*/
|
||||||
const char *egl_error(void);
|
const char *egl_error(void);
|
||||||
|
|
||||||
|
bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface,
|
||||||
|
int *buffer_age);
|
||||||
|
|
||||||
|
// TODO: remove
|
||||||
|
int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -33,6 +33,8 @@ struct wlr_output_cursor {
|
||||||
struct wl_listener surface_destroy;
|
struct wl_listener surface_destroy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define WLR_OUTPUT_PREVIOUS_DAMAGE_COUNT 2
|
||||||
|
|
||||||
struct wlr_output_impl;
|
struct wlr_output_impl;
|
||||||
|
|
||||||
struct wlr_output {
|
struct wlr_output {
|
||||||
|
@ -55,7 +57,7 @@ struct wlr_output {
|
||||||
enum wl_output_transform transform;
|
enum wl_output_transform transform;
|
||||||
|
|
||||||
bool needs_swap;
|
bool needs_swap;
|
||||||
pixman_region32_t damage, previous_damage;
|
pixman_region32_t damage;
|
||||||
float transform_matrix[16];
|
float transform_matrix[16];
|
||||||
|
|
||||||
// Note: some backends may have zero modes
|
// Note: some backends may have zero modes
|
||||||
|
@ -104,13 +106,19 @@ void wlr_output_set_scale(struct wlr_output *output, float scale);
|
||||||
void wlr_output_destroy(struct wlr_output *output);
|
void wlr_output_destroy(struct wlr_output *output);
|
||||||
void wlr_output_effective_resolution(struct wlr_output *output,
|
void wlr_output_effective_resolution(struct wlr_output *output,
|
||||||
int *width, int *height);
|
int *width, int *height);
|
||||||
void wlr_output_make_current(struct wlr_output *output);
|
/**
|
||||||
|
* Makes the output GL context current.
|
||||||
|
*
|
||||||
|
* `buffer_age` is set to the drawing buffer age in number of frames or -1 if
|
||||||
|
* unknown.
|
||||||
|
*/
|
||||||
|
bool wlr_output_make_current(struct wlr_output *output, int *buffer_age);
|
||||||
/**
|
/**
|
||||||
* Swaps the output buffers. If the time of the frame isn't known, set `when` to
|
* Swaps the output buffers. If the time of the frame isn't known, set `when` to
|
||||||
* NULL. If the compositor doesn't support damage tracking, set `damage` to
|
* NULL. If the compositor doesn't support damage tracking, set `damage` to
|
||||||
* NULL.
|
* NULL.
|
||||||
*/
|
*/
|
||||||
void wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when,
|
bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when,
|
||||||
pixman_region32_t *damage);
|
pixman_region32_t *damage);
|
||||||
void wlr_output_set_gamma(struct wlr_output *output,
|
void wlr_output_set_gamma(struct wlr_output *output,
|
||||||
uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b);
|
uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b);
|
||||||
|
|
50
render/egl.c
50
render/egl.c
|
@ -127,18 +127,23 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display,
|
||||||
}
|
}
|
||||||
|
|
||||||
eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl->context);
|
eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl->context);
|
||||||
egl->egl_exts = eglQueryString(egl->display, EGL_EXTENSIONS);
|
egl->egl_exts_str = eglQueryString(egl->display, EGL_EXTENSIONS);
|
||||||
if (strstr(egl->egl_exts, "EGL_WL_bind_wayland_display") == NULL ||
|
egl->gl_exts_str = (const char*) glGetString(GL_EXTENSIONS);
|
||||||
strstr(egl->egl_exts, "EGL_KHR_image_base") == NULL) {
|
|
||||||
|
wlr_log(L_INFO, "Using EGL %d.%d", (int)major, (int)minor);
|
||||||
|
wlr_log(L_INFO, "Supported EGL extensions: %s", egl->egl_exts_str);
|
||||||
|
wlr_log(L_INFO, "Using %s", glGetString(GL_VERSION));
|
||||||
|
wlr_log(L_INFO, "Supported OpenGL ES extensions: %s", egl->gl_exts_str);
|
||||||
|
|
||||||
|
if (strstr(egl->egl_exts_str, "EGL_WL_bind_wayland_display") == NULL ||
|
||||||
|
strstr(egl->egl_exts_str, "EGL_KHR_image_base") == NULL) {
|
||||||
wlr_log(L_ERROR, "Required egl extensions not supported");
|
wlr_log(L_ERROR, "Required egl extensions not supported");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
egl->gl_exts = (const char*) glGetString(GL_EXTENSIONS);
|
egl->egl_exts.buffer_age =
|
||||||
wlr_log(L_INFO, "Using EGL %d.%d", (int)major, (int)minor);
|
strstr(egl->egl_exts_str, "EGL_EXT_buffer_age") != NULL;
|
||||||
wlr_log(L_INFO, "Supported EGL extensions: %s", egl->egl_exts);
|
|
||||||
wlr_log(L_INFO, "Using %s", glGetString(GL_VERSION));
|
|
||||||
wlr_log(L_INFO, "Supported OpenGL ES extensions: %s", egl->gl_exts);
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -208,3 +213,32 @@ EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window) {
|
||||||
}
|
}
|
||||||
return surf;
|
return surf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface) {
|
||||||
|
if (!egl->egl_exts.buffer_age) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLint buffer_age;
|
||||||
|
EGLBoolean ok = eglQuerySurface(egl->display, surface,
|
||||||
|
EGL_BUFFER_AGE_EXT, &buffer_age);
|
||||||
|
if (!ok) {
|
||||||
|
wlr_log(L_ERROR, "Failed to get EGL surface buffer age: %s", egl_error());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer_age;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface,
|
||||||
|
int *buffer_age) {
|
||||||
|
if (!eglMakeCurrent(egl->display, surface, surface, egl->context)) {
|
||||||
|
wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer_age != NULL) {
|
||||||
|
*buffer_age = wlr_egl_get_buffer_age(egl, surface);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -294,11 +294,26 @@ static void render_output(struct roots_output *output) {
|
||||||
wlr_output_set_fullscreen_surface(wlr_output, NULL);
|
wlr_output_set_fullscreen_surface(wlr_output, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int buffer_age = -1;
|
||||||
|
wlr_output_make_current(wlr_output, &buffer_age);
|
||||||
|
|
||||||
pixman_region32_t damage;
|
pixman_region32_t damage;
|
||||||
pixman_region32_init(&damage);
|
pixman_region32_init(&damage);
|
||||||
pixman_region32_union(&damage, &output->damage, &output->previous_damage);
|
if (buffer_age <= 0 || buffer_age - 1 > ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN) {
|
||||||
pixman_region32_intersect_rect(&damage, &damage, 0, 0, wlr_output->width,
|
// Buffer new or too old, damage the whole output
|
||||||
wlr_output->height);
|
pixman_region32_union_rect(&damage, &damage, 0, 0,
|
||||||
|
wlr_output->width, wlr_output->height);
|
||||||
|
} else {
|
||||||
|
pixman_region32_copy(&damage, &output->damage);
|
||||||
|
|
||||||
|
size_t idx = output->previous_damage_idx;
|
||||||
|
for (int i = 0; i < buffer_age - 1; i++) {
|
||||||
|
int j = (idx + i) % ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN;
|
||||||
|
pixman_region32_union(&damage, &damage, &output->previous_damage[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pixman_region32_intersect_rect(&damage, &damage, 0, 0,
|
||||||
|
wlr_output->width, wlr_output->height);
|
||||||
|
|
||||||
if (!pixman_region32_not_empty(&damage) && !wlr_output->needs_swap) {
|
if (!pixman_region32_not_empty(&damage) && !wlr_output->needs_swap) {
|
||||||
// Output doesn't need swap and isn't damaged, skip rendering completely
|
// Output doesn't need swap and isn't damaged, skip rendering completely
|
||||||
|
@ -308,7 +323,6 @@ static void render_output(struct roots_output *output) {
|
||||||
|
|
||||||
wlr_log(L_DEBUG, "render");
|
wlr_log(L_DEBUG, "render");
|
||||||
|
|
||||||
wlr_output_make_current(wlr_output);
|
|
||||||
wlr_renderer_begin(server->renderer, wlr_output);
|
wlr_renderer_begin(server->renderer, wlr_output);
|
||||||
glEnable(GL_SCISSOR_TEST);
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
|
||||||
|
@ -384,7 +398,10 @@ renderer_end:
|
||||||
wlr_renderer_end(server->renderer);
|
wlr_renderer_end(server->renderer);
|
||||||
wlr_output_swap_buffers(wlr_output, &now, &damage);
|
wlr_output_swap_buffers(wlr_output, &now, &damage);
|
||||||
output->frame_pending = true;
|
output->frame_pending = true;
|
||||||
pixman_region32_copy(&output->previous_damage, &output->damage);
|
output->previous_damage_idx += ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN - 1;
|
||||||
|
output->previous_damage_idx %= ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN;
|
||||||
|
pixman_region32_copy(&output->previous_damage[output->previous_damage_idx],
|
||||||
|
&output->damage);
|
||||||
pixman_region32_clear(&output->damage);
|
pixman_region32_clear(&output->damage);
|
||||||
output->last_frame = desktop->last_frame = now;
|
output->last_frame = desktop->last_frame = now;
|
||||||
|
|
||||||
|
@ -551,7 +568,9 @@ void output_add_notify(struct wl_listener *listener, void *data) {
|
||||||
output->wlr_output = wlr_output;
|
output->wlr_output = wlr_output;
|
||||||
wl_list_insert(&desktop->outputs, &output->link);
|
wl_list_insert(&desktop->outputs, &output->link);
|
||||||
pixman_region32_init(&output->damage);
|
pixman_region32_init(&output->damage);
|
||||||
pixman_region32_init(&output->previous_damage);
|
for (size_t i = 0; i < ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN; ++i) {
|
||||||
|
pixman_region32_init(&output->previous_damage[i]);
|
||||||
|
}
|
||||||
|
|
||||||
output->frame.notify = output_handle_frame;
|
output->frame.notify = output_handle_frame;
|
||||||
wl_signal_add(&wlr_output->events.frame, &output->frame);
|
wl_signal_add(&wlr_output->events.frame, &output->frame);
|
||||||
|
@ -610,7 +629,9 @@ void output_remove_notify(struct wl_listener *listener, void *data) {
|
||||||
// sample->compositor);
|
// sample->compositor);
|
||||||
|
|
||||||
pixman_region32_fini(&output->damage);
|
pixman_region32_fini(&output->damage);
|
||||||
pixman_region32_fini(&output->previous_damage);
|
for (size_t i = 0; i < ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN; ++i) {
|
||||||
|
pixman_region32_fini(&output->previous_damage[i]);
|
||||||
|
}
|
||||||
wl_list_remove(&output->link);
|
wl_list_remove(&output->link);
|
||||||
wl_list_remove(&output->frame.link);
|
wl_list_remove(&output->frame.link);
|
||||||
wl_list_remove(&output->mode.link);
|
wl_list_remove(&output->mode.link);
|
||||||
|
|
|
@ -281,7 +281,6 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend,
|
||||||
wl_signal_init(&output->events.transform);
|
wl_signal_init(&output->events.transform);
|
||||||
wl_signal_init(&output->events.destroy);
|
wl_signal_init(&output->events.destroy);
|
||||||
pixman_region32_init(&output->damage);
|
pixman_region32_init(&output->damage);
|
||||||
pixman_region32_init(&output->previous_damage);
|
|
||||||
|
|
||||||
output->display_destroy.notify = handle_display_destroy;
|
output->display_destroy.notify = handle_display_destroy;
|
||||||
wl_display_add_destroy_listener(display, &output->display_destroy);
|
wl_display_add_destroy_listener(display, &output->display_destroy);
|
||||||
|
@ -310,7 +309,6 @@ void wlr_output_destroy(struct wlr_output *output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_region32_fini(&output->damage);
|
pixman_region32_fini(&output->damage);
|
||||||
pixman_region32_fini(&output->previous_damage);
|
|
||||||
|
|
||||||
if (output->impl && output->impl->destroy) {
|
if (output->impl && output->impl->destroy) {
|
||||||
output->impl->destroy(output);
|
output->impl->destroy(output);
|
||||||
|
@ -332,8 +330,8 @@ void wlr_output_effective_resolution(struct wlr_output *output,
|
||||||
*height /= output->scale;
|
*height /= output->scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wlr_output_make_current(struct wlr_output *output) {
|
bool wlr_output_make_current(struct wlr_output *output, int *buffer_age) {
|
||||||
output->impl->make_current(output);
|
return output->impl->make_current(output, buffer_age);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_fullscreen_surface_get_box(struct wlr_output *output,
|
static void output_fullscreen_surface_get_box(struct wlr_output *output,
|
||||||
|
@ -466,17 +464,17 @@ surface_damage_finish:
|
||||||
pixman_region32_fini(&surface_damage);
|
pixman_region32_fini(&surface_damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when,
|
bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when,
|
||||||
pixman_region32_t *damage) {
|
pixman_region32_t *damage) {
|
||||||
wl_signal_emit(&output->events.swap_buffers, damage);
|
wl_signal_emit(&output->events.swap_buffers, damage);
|
||||||
|
|
||||||
pixman_region32_t *render_damage = damage;
|
pixman_region32_t *render_damage = damage;
|
||||||
if (damage == NULL) {
|
if (damage == NULL) {
|
||||||
|
// Damage tracking not supported, repaint the whole output
|
||||||
pixman_region32_t output_damage;
|
pixman_region32_t output_damage;
|
||||||
pixman_region32_init(&output_damage);
|
pixman_region32_init(&output_damage);
|
||||||
pixman_region32_copy(&output_damage, &output->damage);
|
pixman_region32_union_rect(&output_damage, &output_damage,
|
||||||
pixman_region32_union(&output_damage, &output_damage,
|
0, 0, output->width, output->height);
|
||||||
&output->previous_damage);
|
|
||||||
render_damage = &output_damage;
|
render_damage = &output_damage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,14 +501,18 @@ void wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: provide `damage` (not `render_damage`) to backend
|
// TODO: provide `damage` (not `render_damage`) to backend
|
||||||
output->impl->swap_buffers(output);
|
if (!output->impl->swap_buffers(output)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
output->needs_swap = false;
|
output->needs_swap = false;
|
||||||
pixman_region32_copy(&output->previous_damage, &output->damage);
|
|
||||||
pixman_region32_clear(&output->damage);
|
pixman_region32_clear(&output->damage);
|
||||||
|
|
||||||
if (damage == NULL) {
|
if (damage == NULL) {
|
||||||
pixman_region32_fini(render_damage);
|
pixman_region32_fini(render_damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wlr_output_set_gamma(struct wlr_output *output,
|
void wlr_output_set_gamma(struct wlr_output *output,
|
||||||
|
|
|
@ -47,7 +47,6 @@ static void output_frame_notify(struct wl_listener *listener, void *_data) {
|
||||||
struct wlr_renderer *renderer = state->screenshot->screenshooter->renderer;
|
struct wlr_renderer *renderer = state->screenshot->screenshooter->renderer;
|
||||||
struct wlr_output *output = state->screenshot->output;
|
struct wlr_output *output = state->screenshot->output;
|
||||||
|
|
||||||
wlr_output_make_current(output);
|
|
||||||
wlr_renderer_read_pixels(renderer, 0, 0, output->width, output->height,
|
wlr_renderer_read_pixels(renderer, 0, 0, output->width, output->height,
|
||||||
state->pixels);
|
state->pixels);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue