Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/next' into fix-mask-image
Browse files Browse the repository at this point in the history
  • Loading branch information
Monsterovich committed Jun 17, 2023
2 parents 410ca96 + 7fc9436 commit fcf3a9e
Show file tree
Hide file tree
Showing 30 changed files with 986 additions and 210 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
languages: ${{ matrix.language }}

# Install dependencies
- run: sudo apt update && sudo apt install libxext-dev libxcb1-dev libxcb-dpms0-dev libxcb-damage0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-render-util0-dev libxcb-render0-dev libxcb-randr0-dev libxcb-composite0-dev libxcb-image0-dev libxcb-present-dev libxcb-glx0-dev libpixman-1-dev libdbus-1-dev libconfig-dev libgl1-mesa-dev libpcre2-dev libevdev-dev uthash-dev libev-dev libx11-xcb-dev meson ninja-build
- run: sudo apt update && sudo apt install libxext-dev libxcb1-dev libxcb-dpms0-dev libxcb-damage0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-render-util0-dev libxcb-render0-dev libxcb-randr0-dev libxcb-composite0-dev libxcb-image0-dev libxcb-present-dev libxcb-glx0-dev libxcb-util-dev libpixman-1-dev libdbus-1-dev libconfig-dev libgl1-mesa-dev libpcre2-dev libevdev-dev uthash-dev libev-dev libx11-xcb-dev meson ninja-build
if: ${{ matrix.language == 'cpp' }}

# Autobuild
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
picom
=====

[![circleci](https://circleci.com/gh/yshui/picom.svg?style=shield)](https://circleci.com/gh/yshui/picom)
[![codecov](https://codecov.io/gh/yshui/picom/branch/next/graph/badge.svg?token=NRSegi0Gze)](https://codecov.io/gh/yshui/picom)
[![chat on discord](https://img.shields.io/discord/1106224720833159198?logo=discord)](https://discord.gg/uqmNX6dR)

__picom__ is a compositor for X, and a [fork of Compton](History.md).

**This is a development branch, bugs to be expected**

You can leave your feedback or thoughts in the [discussion tab](https://github.com/yshui/picom/discussions).
You can leave your feedback or thoughts in the [discussion tab](https://github.com/yshui/picom/discussions), or chat with other users on [discord](https://discord.gg/SY5JJzPgME)!

## Change Log

Expand All @@ -22,6 +26,7 @@ Assuming you already have all the usual building tools installed (e.g. gcc, pyth
* libXext
* xproto
* xcb
* xcb-util
* xcb-damage
* xcb-dpms
* xcb-xfixes
Expand Down
6 changes: 6 additions & 0 deletions man/picom.1.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,15 @@ OPTIONS
*--corner-radius* 'VALUE'::
Sets the radius of rounded window corners. When > 0, the compositor will round the corners of windows. Does not interact well with *--transparent-clipping*. (defaults to 0).

*--corner-radius-rules* 'RADIUS':'CONDITION'::
Specify a list of corner radius rules. Overrides the corner radii of matching windows. This option takes precedence over the *--rounded-corners-exclude* option, and also overrides the default exclusion of fullscreen windows. The condition has the same format as *--opacity-rule*.

*--rounded-corners-exclude* 'CONDITION'::
Exclude conditions for rounded corners.

*--no-frame-pacing*::
Disable vsync-aware frame pacing. By default, the compositor tries to make sure it only renders once per vblank interval, and also the render happens as late as possible to minimize the latency from updates to the screen. However this can sometimes cause stuttering, or even lowered frame rate. This option can be used to disable frame pacing.

*--mark-wmwin-focused*::
Try to detect WM windows (a non-override-redirect window with no child that has 'WM_STATE') and mark them as active.

Expand Down
34 changes: 27 additions & 7 deletions src/backend/backend.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#include <inttypes.h>
#include <xcb/sync.h>
#include <xcb/xcb.h>

Expand Down Expand Up @@ -81,7 +82,10 @@ void handle_device_reset(session_t *ps) {
}

/// paint all windows
void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
void paint_all_new(session_t *ps, struct managed_win *t) {
struct timespec now = get_time_timespec();
auto paint_all_start_us =
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
if (ps->backend_data->ops->device_status &&
ps->backend_data->ops->device_status(ps->backend_data) != DEVICE_STATUS_NORMAL) {
return handle_device_reset(ps);
Expand All @@ -96,16 +100,17 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
ps->xsync_exists = false;
}
}

now = get_time_timespec();
auto after_sync_fence_us =
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
log_trace("Time spent on sync fence: %" PRIu64 " us",
after_sync_fence_us - paint_all_start_us);
// All painting will be limited to the damage, if _some_ of
// the paints bleed out of the damage region, it will destroy
// part of the image we want to reuse
region_t reg_damage;
if (!ignore_damage) {
reg_damage = get_damage(ps, ps->o.monitor_repaint || !ps->o.use_damage);
} else {
pixman_region32_init(&reg_damage);
pixman_region32_copy(&reg_damage, &ps->screen_reg);
}
reg_damage = get_damage(ps, ps->o.monitor_repaint || !ps->o.use_damage);

if (!pixman_region32_not_empty(&reg_damage)) {
pixman_region32_fini(&reg_damage);
Expand Down Expand Up @@ -181,6 +186,21 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
region_t reg_shadow_clip;
pixman_region32_init(&reg_shadow_clip);

now = get_time_timespec();
auto after_damage_us = (uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
log_trace("Getting damage took %" PRIu64 " us", after_damage_us - after_sync_fence_us);
if (ps->next_render > 0) {
log_trace("Render schedule deviation: %ld us (%s) %" PRIu64 " %ld",
labs((long)after_damage_us - (long)ps->next_render),
after_damage_us < ps->next_render ? "early" : "late",
after_damage_us, ps->next_render);
ps->last_schedule_delay = 0;
if (after_damage_us > ps->next_render) {
ps->last_schedule_delay = after_damage_us - ps->next_render;
}
}
ps->did_render = true;

if (ps->backend_data->ops->prepare) {
ps->backend_data->ops->prepare(ps->backend_data, &reg_paint);
}
Expand Down
11 changes: 9 additions & 2 deletions src/backend/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,14 @@ struct backend_operations {
/// Optional
int (*buffer_age)(backend_t *backend_data);

/// Get the render time of the last frame. If the render is still in progress,
/// returns false. The time is returned in `ts`. Frames are delimited by the
/// present() calls. i.e. after a present() call, last_render_time() should start
/// reporting the time of the just presen1ted frame.
///
/// Optional, if not available, the most conservative estimation will be used.
bool (*last_render_time)(backend_t *backend_data, struct timespec *ts);

/// The maximum number buffer_age might return.
int max_buffer_age;

Expand Down Expand Up @@ -363,5 +371,4 @@ struct backend_operations {

extern struct backend_operations *backend_list[];

void paint_all_new(session_t *ps, struct managed_win *const t, bool ignore_damage)
attr_nonnull(1);
void paint_all_new(session_t *ps, struct managed_win *const t) attr_nonnull(1);
8 changes: 5 additions & 3 deletions src/backend/backend_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,20 +294,22 @@ bool build_shadow(xcb_connection_t *c, xcb_drawable_t d, double opacity, const i
void *default_backend_render_shadow(backend_t *backend_data, int width, int height,
struct backend_shadow_context *sctx, struct color color) {
const conv *kernel = (void *)sctx;
xcb_pixmap_t shadow_pixel = solid_picture(backend_data->c, backend_data->root, true,
1, color.red, color.green, color.blue),
shadow = XCB_NONE;
xcb_render_picture_t shadow_pixel = solid_picture(
backend_data->c, backend_data->root, true, 1, color.red, color.green, color.blue);
xcb_pixmap_t shadow = XCB_NONE;
xcb_render_picture_t pict = XCB_NONE;

if (!build_shadow(backend_data->c, backend_data->root, color.alpha, width, height,
kernel, shadow_pixel, &shadow, &pict)) {
xcb_render_free_picture(backend_data->c, shadow_pixel);
return NULL;
}

auto visual = x_get_visual_for_standard(backend_data->c, XCB_PICT_STANDARD_ARGB_32);
void *ret = backend_data->ops->bind_pixmap(
backend_data, shadow, x_get_visual_info(backend_data->c, visual), true);
xcb_render_free_picture(backend_data->c, pict);
xcb_render_free_picture(backend_data->c, shadow_pixel);
return ret;
}

Expand Down
2 changes: 0 additions & 2 deletions src/backend/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
/// Apply driver specified global workarounds. It's safe to call this multiple times.
void apply_driver_workarounds(struct session *ps, enum driver driver) {
if (driver & DRIVER_NVIDIA) {
// setenv("__GL_YIELD", "usleep", true);
setenv("__GL_MaxFramesAllowed", "1", true);
ps->o.xrender_sync_fence = true;
}
}
Expand Down
12 changes: 10 additions & 2 deletions src/backend/dummy/dummy.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct dummy_image {
xcb_pixmap_t pixmap;
bool transparent;
int *refcount;
bool owned;
UT_hash_handle hh;
};

Expand All @@ -42,6 +43,9 @@ void dummy_deinit(struct backend_base *data) {
log_warn("Backend image for pixmap %#010x is not freed", img->pixmap);
HASH_DEL(dummy->images, img);
free(img->refcount);
if (img->owned) {
xcb_free_pixmap(data->c, img->pixmap);
}
free(img);
}
free(dummy);
Expand Down Expand Up @@ -82,7 +86,7 @@ bool dummy_blur(struct backend_base *backend_data attr_unused, double opacity at
}

void *dummy_bind_pixmap(struct backend_base *base, xcb_pixmap_t pixmap,
struct xvisual_info fmt, bool owned attr_unused) {
struct xvisual_info fmt, bool owned) {
auto dummy = (struct dummy_data *)base;
struct dummy_image *img = NULL;
HASH_FIND_INT(dummy->images, &pixmap, img);
Expand All @@ -96,6 +100,7 @@ void *dummy_bind_pixmap(struct backend_base *base, xcb_pixmap_t pixmap,
img->transparent = fmt.alpha_size != 0;
img->refcount = ccalloc(1, int);
*img->refcount = 1;
img->owned = owned;

HASH_ADD_INT(dummy->images, pixmap, img);
return (void *)img;
Expand All @@ -112,6 +117,9 @@ void dummy_release_image(backend_t *base, void *image) {
if (*img->refcount == 0) {
HASH_DEL(dummy->images, img);
free(img->refcount);
if (img->owned) {
xcb_free_pixmap(base->c, img->pixmap);
}
free(img);
}
}
Expand Down Expand Up @@ -162,7 +170,7 @@ void dummy_destroy_blur_context(struct backend_base *base attr_unused, void *ctx
}

void dummy_get_blur_size(void *ctx attr_unused, int *width, int *height) {
// These numbers are arbitrary, to make sure the reisze_region code path is
// These numbers are arbitrary, to make sure the resize_region code path is
// covered.
*width = 5;
*height = 5;
Expand Down
32 changes: 28 additions & 4 deletions src/backend/gl/egl.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,30 @@ static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageProc = NULL;
static PFNEGLGETPLATFORMDISPLAYPROC eglGetPlatformDisplayProc = NULL;
static PFNEGLCREATEPLATFORMWINDOWSURFACEPROC eglCreatePlatformWindowSurfaceProc = NULL;

const char *eglGetErrorString(EGLint error) {
#define CASE_STR(value) \
case value: return #value;
switch (error) {
CASE_STR(EGL_SUCCESS)
CASE_STR(EGL_NOT_INITIALIZED)
CASE_STR(EGL_BAD_ACCESS)
CASE_STR(EGL_BAD_ALLOC)
CASE_STR(EGL_BAD_ATTRIBUTE)
CASE_STR(EGL_BAD_CONTEXT)
CASE_STR(EGL_BAD_CONFIG)
CASE_STR(EGL_BAD_CURRENT_SURFACE)
CASE_STR(EGL_BAD_DISPLAY)
CASE_STR(EGL_BAD_SURFACE)
CASE_STR(EGL_BAD_MATCH)
CASE_STR(EGL_BAD_PARAMETER)
CASE_STR(EGL_BAD_NATIVE_PIXMAP)
CASE_STR(EGL_BAD_NATIVE_WINDOW)
CASE_STR(EGL_CONTEXT_LOST)
default: return "Unknown";
}
#undef CASE_STR
}

/**
* Free a glx_texture_t.
*/
Expand Down Expand Up @@ -283,7 +307,8 @@ egl_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b
eglpixmap->owned = owned;

if (eglpixmap->image == EGL_NO_IMAGE) {
log_error("Failed to create eglpixmap for pixmap %#010x", pixmap);
log_error("Failed to create eglpixmap for pixmap %#010x: %s", pixmap,
eglGetErrorString(eglGetError()));
goto err;
}

Expand Down Expand Up @@ -320,9 +345,6 @@ static void egl_present(backend_t *base, const region_t *region attr_unused) {
struct egl_data *gd = (void *)base;
gl_present(base, region);
eglSwapBuffers(gd->display, gd->target_win);
if (!gd->gl.is_nvidia) {
glFinish();
}
}

static int egl_buffer_age(backend_t *base) {
Expand Down Expand Up @@ -372,6 +394,7 @@ struct backend_operations egl_ops = {
.deinit = egl_deinit,
.bind_pixmap = egl_bind_pixmap,
.release_image = gl_release_image,
.prepare = gl_prepare,
.compose = gl_compose,
.image_op = gl_image_op,
.set_image_property = gl_set_image_property,
Expand All @@ -380,6 +403,7 @@ struct backend_operations egl_ops = {
.is_image_transparent = default_is_image_transparent,
.present = egl_present,
.buffer_age = egl_buffer_age,
.last_render_time = gl_last_render_time,
.create_shadow_context = gl_create_shadow_context,
.destroy_shadow_context = gl_destroy_shadow_context,
.render_shadow = backend_render_shadow_from_mask,
Expand Down
36 changes: 35 additions & 1 deletion src/backend/gl/gl_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
#include "backend/backend_common.h"
#include "backend/gl/gl_common.h"

void gl_prepare(backend_t *base, const region_t *reg attr_unused) {
auto gd = (struct gl_data *)base;
glBeginQuery(GL_TIME_ELAPSED, gd->frame_timing[gd->current_frame_timing]);
}

GLuint gl_create_shader(GLenum shader_type, const char *shader_str) {
log_trace("===\n%s\n===", shader_str);

Expand Down Expand Up @@ -800,6 +805,9 @@ uint64_t gl_get_shader_attributes(backend_t *backend_data attr_unused, void *sha
}

bool gl_init(struct gl_data *gd, session_t *ps) {
glGenQueries(2, gd->frame_timing);
gd->current_frame_timing = 0;

// Initialize GLX data structure
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
Expand Down Expand Up @@ -945,7 +953,7 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
const char *vendor = (const char *)glGetString(GL_VENDOR);
log_debug("GL_VENDOR = %s", vendor);
if (strcmp(vendor, "NVIDIA Corporation") == 0) {
log_info("GL vendor is NVIDIA, don't use glFinish");
log_info("GL vendor is NVIDIA, enable xrender sync fence.");
gd->is_nvidia = true;
} else {
gd->is_nvidia = false;
Expand All @@ -968,6 +976,9 @@ void gl_deinit(struct gl_data *gd) {
gd->default_shader = NULL;
}

glDeleteTextures(1, &gd->default_mask_texture);
glDeleteTextures(1, &gd->back_texture);

gl_check_err();
}

Expand Down Expand Up @@ -1154,10 +1165,33 @@ void gl_present(backend_t *base, const region_t *region) {
glDeleteBuffers(2, bo);
glDeleteVertexArrays(1, &vao);

glEndQuery(GL_TIME_ELAPSED);
gd->current_frame_timing ^= 1;

gl_check_err();

free(coord);
free(indices);
}

bool gl_last_render_time(backend_t *base, struct timespec *ts) {
auto gd = (struct gl_data *)base;
GLint available = 0;
glGetQueryObjectiv(gd->frame_timing[gd->current_frame_timing ^ 1],
GL_QUERY_RESULT_AVAILABLE, &available);
if (!available) {
return false;
}

GLuint64 time;
glGetQueryObjectui64v(gd->frame_timing[gd->current_frame_timing ^ 1],
GL_QUERY_RESULT, &time);
ts->tv_sec = (long)(time / 1000000000);
ts->tv_nsec = (long)(time % 1000000000);
gl_check_err();
return true;
}

bool gl_image_op(backend_t *base, enum image_operations op, void *image_data,
const region_t *reg_op, const region_t *reg_visible attr_unused, void *arg) {
struct backend_image *tex = image_data;
Expand Down
Loading

0 comments on commit fcf3a9e

Please sign in to comment.