mirror of
https://github.com/yshui/picom.git
synced 2025-04-21 18:03:02 -04:00
commit
c282bb59f2
49 changed files with 1317 additions and 879 deletions
|
@ -26,12 +26,14 @@
|
|||
! fullscreen
|
||||
border_width = 0
|
||||
```
|
||||
* picom now has a rudimentary plugin system. At the moment, the only thing you can do with it is loading custom backends.
|
||||
|
||||
## Notable changes
|
||||
|
||||
* `override_redirect` in rules now only matches top-level windows that doesn't have a client window. Some window managers (e.g. awesome) set override_redirect for all window manager frame windows, causing this rule to match against everything (#625).
|
||||
* Marginally improve performance when resizing/opening/closing windows. (#1190)
|
||||
* Type and format specifiers are no longer used in rules. These specifiers are what you put after the colon (':') in rules, e.g. the `:32c` in `"_GTK_FRAME_EXTENTS@:32c"`. Now this information is ignored and the property is matched regardless of format or type.
|
||||
* `backend` is now a required option. picom will not start if one is not specified explicitly.
|
||||
|
||||
## Deprecated features
|
||||
|
||||
|
|
3
include/meson.build
Normal file
3
include/meson.build
Normal file
|
@ -0,0 +1,3 @@
|
|||
# SPDX-License-Identifier: MPL-2.0
|
||||
# Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||
subdirs('picom')
|
33
include/picom/api.h
Normal file
33
include/picom/api.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define PICOM_API_MAJOR (0UL)
|
||||
#define PICOM_API_MINOR (1UL)
|
||||
|
||||
struct backend_base;
|
||||
|
||||
/// The entry point of a backend plugin. Called after the backend is initialized.
|
||||
typedef void (*picom_backend_plugin_entrypoint)(struct backend_base *backend, void *user_data);
|
||||
struct picom_api {
|
||||
/// Add a plugin for a specific backend. The plugin's entry point will be called
|
||||
/// when the specified backend is initialized.
|
||||
///
|
||||
/// @param backend_name The name of the backend to add the plugin to.
|
||||
/// @param major The major version of the backend API interface this plugin
|
||||
/// is compatible with.
|
||||
/// @param minor The minor version of the backend API interface this plugin
|
||||
/// is compatible with.
|
||||
/// @param entrypoint The entry point of the plugin.
|
||||
/// @param user_data The user data to pass to the plugin's entry point.
|
||||
bool (*add_backend_plugin)(const char *backend_name, uint64_t major, uint64_t minor,
|
||||
picom_backend_plugin_entrypoint entrypoint,
|
||||
void *user_data);
|
||||
};
|
||||
|
||||
const struct picom_api *
|
||||
picom_api_get_interfaces(uint64_t major, uint64_t minor, const char *context);
|
491
include/picom/backend.h
Normal file
491
include/picom/backend.h
Normal file
|
@ -0,0 +1,491 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pixman-1/pixman.h>
|
||||
#include <stdbool.h>
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define PICOM_BACKEND_MAJOR (1UL)
|
||||
#define PICOM_BACKEND_MINOR (0UL)
|
||||
#define PICOM_BACKEND_MAKE_VERSION(major, minor) ((major) * 1000 + (minor))
|
||||
|
||||
typedef pixman_region32_t region_t;
|
||||
|
||||
struct xvisual_info {
|
||||
/// Bit depth of the red component
|
||||
int red_size;
|
||||
/// Bit depth of the green component
|
||||
int green_size;
|
||||
/// Bit depth of the blue component
|
||||
int blue_size;
|
||||
/// Bit depth of the alpha component
|
||||
int alpha_size;
|
||||
/// The depth of X visual
|
||||
int visual_depth;
|
||||
|
||||
xcb_visualid_t visual;
|
||||
};
|
||||
|
||||
typedef struct session session_t;
|
||||
struct managed_win;
|
||||
|
||||
struct ev_loop;
|
||||
struct backend_operations;
|
||||
|
||||
typedef struct backend_base backend_t;
|
||||
|
||||
// This mimics OpenGL's ARB_robustness extension, which enables detection of GPU context
|
||||
// resets.
|
||||
// See: https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_robustness.txt, section
|
||||
// 2.6 "Graphics Reset Recovery".
|
||||
enum device_status {
|
||||
DEVICE_STATUS_NORMAL,
|
||||
DEVICE_STATUS_RESETTING,
|
||||
};
|
||||
|
||||
enum shader_attributes {
|
||||
// Whether the shader needs to be render regardless of whether the window is
|
||||
// updated.
|
||||
SHADER_ATTRIBUTE_ANIMATED = 1,
|
||||
};
|
||||
|
||||
struct gaussian_blur_args {
|
||||
int size;
|
||||
double deviation;
|
||||
};
|
||||
|
||||
struct box_blur_args {
|
||||
int size;
|
||||
};
|
||||
|
||||
struct kernel_blur_args {
|
||||
struct conv **kernels;
|
||||
int kernel_count;
|
||||
};
|
||||
|
||||
struct dual_kawase_blur_args {
|
||||
int size;
|
||||
int strength;
|
||||
};
|
||||
|
||||
typedef struct image_handle {
|
||||
// Intentionally left blank
|
||||
} *image_handle;
|
||||
|
||||
/// A mask for various backend operations.
|
||||
///
|
||||
/// The mask is composed of both a mask region and a mask image. The resulting mask
|
||||
/// is the intersection of the two. The mask image can be modified by the `corner_radius`
|
||||
/// and `inverted` properties. Note these properties have no effect on the mask region.
|
||||
struct backend_mask_image {
|
||||
/// Mask image, can be NULL.
|
||||
///
|
||||
/// Mask image must be an image that was created with the
|
||||
/// `BACKEND_IMAGE_FORMAT_MASK` format. Using an image with a wrong format as mask
|
||||
/// is undefined behavior.
|
||||
image_handle image;
|
||||
/// Corner radius of the mask image, the corners of the mask image will be
|
||||
/// rounded.
|
||||
double corner_radius;
|
||||
/// Origin of the mask image, in the source image's coordinate.
|
||||
ivec2 origin;
|
||||
/// Whether the mask image should be inverted.
|
||||
bool inverted;
|
||||
};
|
||||
|
||||
struct backend_blur_args {
|
||||
/// The blur context
|
||||
void *blur_context;
|
||||
/// The source mask for the blur operation, may be NULL. Only parts of the source
|
||||
/// image covered by the mask should participate in the blur operation.
|
||||
const struct backend_mask_image *source_mask;
|
||||
/// Region of the target image that will be covered by the blur operation, in the
|
||||
/// source image's coordinate.
|
||||
const region_t *target_mask;
|
||||
/// Source image
|
||||
image_handle source_image;
|
||||
/// Opacity of the blurred image
|
||||
double opacity;
|
||||
};
|
||||
|
||||
struct backend_blit_args {
|
||||
/// Source image, can be NULL.
|
||||
image_handle source_image;
|
||||
/// Mask for the source image. may be NULL. Only contents covered by the mask
|
||||
/// should participate in the blit operation. This applies to the source image
|
||||
/// before it's scaled.
|
||||
const struct backend_mask_image *source_mask;
|
||||
/// Mask for the target image. Only regions of the target image covered by this
|
||||
/// mask should be modified. This is the target's coordinate system.
|
||||
const region_t *target_mask;
|
||||
/// Custom shader for this blit operation.
|
||||
void *shader;
|
||||
/// Opacity of the source image.
|
||||
double opacity;
|
||||
/// Dim level of the source image.
|
||||
double dim;
|
||||
/// Brightness limit of the source image. Source image
|
||||
/// will be normalized so that the maximum brightness is
|
||||
/// this value.
|
||||
double max_brightness;
|
||||
/// Scale factor for the horizontal and vertical direction (X for horizontal,
|
||||
/// Y for vertical).
|
||||
vec2 scale;
|
||||
/// Corner radius of the source image BEFORE scaling. The corners of
|
||||
/// the source image will be rounded.
|
||||
double corner_radius;
|
||||
/// Effective size of the source image BEFORE scaling, set where the corners
|
||||
/// of the image are.
|
||||
ivec2 effective_size;
|
||||
/// Border width of the source image BEFORE scaling. This is used with
|
||||
/// `corner_radius` to create a border for the rounded corners.
|
||||
/// Setting this has no effect if `corner_radius` is 0.
|
||||
int border_width;
|
||||
/// Whether the source image should be inverted.
|
||||
bool color_inverted;
|
||||
};
|
||||
|
||||
enum backend_image_format {
|
||||
/// A format that can be used for normal rendering, and binding
|
||||
/// X pixmaps.
|
||||
/// Images created with `bind_pixmap` have this format automatically.
|
||||
BACKEND_IMAGE_FORMAT_PIXMAP,
|
||||
/// Like `BACKEND_IMAGE_FORMAT_PIXMAP`, but the image has a higher
|
||||
/// precision. Support is optional.
|
||||
BACKEND_IMAGE_FORMAT_PIXMAP_HIGH,
|
||||
/// A format that can be used for masks.
|
||||
BACKEND_IMAGE_FORMAT_MASK,
|
||||
};
|
||||
|
||||
enum backend_image_capability {
|
||||
/// Image can be sampled from. This is required for `blit` and `blur` source
|
||||
/// images. All images except the back buffer should have this capability.
|
||||
/// Note that `copy_area` should work without this capability, this is so that
|
||||
/// blurring the back buffer could be done.
|
||||
BACKEND_IMAGE_CAP_SRC = 1 << 0,
|
||||
/// Image can be rendered to. This is required for target images of any operation.
|
||||
/// All images except bound X pixmaps should have this capability.
|
||||
BACKEND_IMAGE_CAP_DST = 1 << 1,
|
||||
};
|
||||
|
||||
enum backend_command_op {
|
||||
BACKEND_COMMAND_INVALID = -1,
|
||||
BACKEND_COMMAND_BLIT,
|
||||
BACKEND_COMMAND_BLUR,
|
||||
BACKEND_COMMAND_COPY_AREA,
|
||||
};
|
||||
|
||||
/// Symbolic references used as render command source images. The actual `image_handle`
|
||||
/// will later be filled in by the renderer using this symbolic reference.
|
||||
enum backend_command_source {
|
||||
BACKEND_COMMAND_SOURCE_WINDOW,
|
||||
BACKEND_COMMAND_SOURCE_SHADOW,
|
||||
BACKEND_COMMAND_SOURCE_BACKGROUND,
|
||||
};
|
||||
|
||||
// TODO(yshui) might need better names
|
||||
|
||||
struct backend_command {
|
||||
enum backend_command_op op;
|
||||
ivec2 origin;
|
||||
enum backend_command_source source;
|
||||
union {
|
||||
struct {
|
||||
struct backend_blit_args blit;
|
||||
/// Region of the screen that will be covered by this blit
|
||||
/// operations, in screen coordinates.
|
||||
region_t opaque_region;
|
||||
};
|
||||
struct {
|
||||
image_handle source_image;
|
||||
const region_t *region;
|
||||
} copy_area;
|
||||
struct backend_blur_args blur;
|
||||
};
|
||||
/// Source mask for the operation.
|
||||
/// If the `source_mask` of the operation's argument points to this, a mask image
|
||||
/// will be created for the operation for the renderer.
|
||||
struct backend_mask_image source_mask;
|
||||
/// Target mask for the operation.
|
||||
region_t target_mask;
|
||||
};
|
||||
|
||||
enum backend_quirk {
|
||||
/// Backend cannot do blur quickly. The compositor will avoid using blur to create
|
||||
/// shadows on this backend
|
||||
BACKEND_QUIRK_SLOW_BLUR = 1 << 0,
|
||||
};
|
||||
|
||||
struct backend_operations {
|
||||
// =========== Initialization ===========
|
||||
|
||||
/// Initialize the backend, prepare for rendering to the target window.
|
||||
backend_t *(*init)(session_t *, xcb_window_t) __attribute__((nonnull(1)));
|
||||
void (*deinit)(backend_t *backend_data) __attribute__((nonnull(1)));
|
||||
|
||||
/// Called when rendering will be stopped for an unknown amount of
|
||||
/// time (e.g. when screen is unredirected). Free some resources.
|
||||
///
|
||||
/// Optional, not yet used
|
||||
void (*pause)(backend_t *backend_data, session_t *ps);
|
||||
|
||||
/// Called before rendering is resumed
|
||||
///
|
||||
/// Optional, not yet used
|
||||
void (*resume)(backend_t *backend_data, session_t *ps);
|
||||
|
||||
/// Called when root window size changed. All existing image data ever
|
||||
/// returned by this backend should remain valid after this call
|
||||
/// returns.
|
||||
///
|
||||
/// Optional
|
||||
void (*root_change)(backend_t *backend_data, session_t *ps);
|
||||
|
||||
// =========== Rendering ============
|
||||
|
||||
/// Called before when a new frame starts.
|
||||
///
|
||||
/// Optional
|
||||
void (*prepare)(backend_t *backend_data, const region_t *reg_damage);
|
||||
|
||||
/// Multiply the alpha channel of the target image by a given value.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param target an image handle, cannot be NULL.
|
||||
/// @param alpha the alpha value to multiply
|
||||
/// @param region the region to apply the alpha, in the target image's
|
||||
/// coordinate.
|
||||
bool (*apply_alpha)(struct backend_base *backend_data, image_handle target,
|
||||
double alpha, const region_t *region)
|
||||
__attribute__((nonnull(1, 2, 4)));
|
||||
|
||||
/// Copy pixels from a source image on to the target image.
|
||||
///
|
||||
/// Some effects may be applied. If the region specified by the mask
|
||||
/// contains parts that are outside the source image, the source image
|
||||
/// will be repeated to fit.
|
||||
///
|
||||
/// Source and target MUST NOT be the same image.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param origin the origin of the operation, in the target image's
|
||||
/// coordinate.
|
||||
/// @param target an image handle, cannot be NULL.
|
||||
/// @param args arguments for blit
|
||||
/// @return whether the operation is successful
|
||||
bool (*blit)(struct backend_base *backend_data, ivec2 origin, image_handle target,
|
||||
const struct backend_blit_args *args) __attribute__((nonnull(1, 3, 4)));
|
||||
|
||||
/// Blur a given region of a source image and store the result in the
|
||||
/// target image.
|
||||
///
|
||||
/// The blur operation might access pixels outside the mask region, the
|
||||
/// amount of pixels accessed can be queried with `get_blur_size`. If
|
||||
/// pixels outside the source image are accessed, the result will be
|
||||
/// clamped to the edge of the source image.
|
||||
///
|
||||
/// Source and target may be the same image.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param origin the origin of the operation, in the target image's
|
||||
/// coordinate.
|
||||
/// @param target an image handle, cannot be NULL.
|
||||
/// @param args argument for blur
|
||||
/// @return whether the operation is successful
|
||||
bool (*blur)(struct backend_base *backend_data, ivec2 origin, image_handle target,
|
||||
const struct backend_blur_args *args) __attribute__((nonnull(1, 3, 4)));
|
||||
|
||||
/// Direct copy of pixels from a source image on to the target image.
|
||||
/// This is a simpler version of `blit`, without any effects. Note unlike `blit`,
|
||||
/// if `region` tries to sample from outside the source image, instead of
|
||||
/// repeating, the result will be clamped to the edge of the source image.
|
||||
/// Blending should not be applied for the copy.
|
||||
///
|
||||
/// Source and target MUST NOT be the same image.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param origin the origin of the operation, in the target image's
|
||||
/// coordinate.
|
||||
/// @param target an image handle, cannot be NULL.
|
||||
/// @param source an image handle, cannot be NULL.
|
||||
/// @param region the region to copy, in the target image's coordinate.
|
||||
/// @return whether the operation is successful
|
||||
bool (*copy_area)(struct backend_base *backend_data, ivec2 origin,
|
||||
image_handle target, image_handle source, const region_t *region)
|
||||
__attribute__((nonnull(1, 3, 4, 5)));
|
||||
|
||||
/// Similar to `copy_area`, but is specialized for copying from a higher
|
||||
/// precision format to a lower precision format. It has 2 major differences from
|
||||
/// `copy_area`:
|
||||
///
|
||||
/// 1. This function _may_ use dithering when copying from a higher precision
|
||||
/// format to a lower precision format. But this is not required.
|
||||
/// 2. This function only needs to support copying from an image with the SRC
|
||||
/// capability. Unlike `copy_area`, which supports copying from any image.
|
||||
///
|
||||
/// It's perfectly legal to have this pointing to the same function as
|
||||
/// `copy_area`, if the backend doesn't support dithering.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param origin the origin of the operation, in the target image's
|
||||
/// coordinate.
|
||||
/// @param target an image handle, cannot be NULL.
|
||||
/// @param source an image handle, cannot be NULL.
|
||||
/// @param region the region to copy, in the target image's coordinate.
|
||||
/// @return whether the operation is successful
|
||||
bool (*copy_area_quantize)(struct backend_base *backend_data, ivec2 origin,
|
||||
image_handle target, image_handle source,
|
||||
const region_t *region)
|
||||
__attribute__((nonnull(1, 3, 4, 5)));
|
||||
|
||||
/// Initialize an image with a given color value. If the image has a mask format,
|
||||
/// only the alpha channel of the color is used.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param target an image handle, cannot be NULL.
|
||||
/// @param color the color to fill the image with
|
||||
/// @return whether the operation is successful
|
||||
bool (*clear)(struct backend_base *backend_data, image_handle target,
|
||||
struct color color) __attribute__((nonnull(1, 2)));
|
||||
|
||||
/// Present the back buffer to the target window. Ideally the backend should keep
|
||||
/// track of the region of the back buffer that has been updated, and use relevant
|
||||
/// mechanism (when possible) to present only the updated region.
|
||||
bool (*present)(struct backend_base *backend_data) __attribute__((nonnull(1)));
|
||||
|
||||
// ============ Resource management ===========
|
||||
|
||||
/// Create a shader object from a shader source.
|
||||
///
|
||||
/// Optional
|
||||
void *(*create_shader)(backend_t *backend_data, const char *source)
|
||||
__attribute__((nonnull(1, 2)));
|
||||
|
||||
/// Free a shader object.
|
||||
///
|
||||
/// Required if create_shader is present.
|
||||
void (*destroy_shader)(backend_t *backend_data, void *shader)
|
||||
__attribute__((nonnull(1, 2)));
|
||||
|
||||
/// Create a new, uninitialized image with the given format and size.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param format the format of the image
|
||||
/// @param size the size of the image
|
||||
image_handle (*new_image)(struct backend_base *backend_data,
|
||||
enum backend_image_format format, ivec2 size)
|
||||
__attribute__((nonnull(1)));
|
||||
|
||||
/// Bind a X pixmap to the backend's internal image data structure.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param pixmap X pixmap to bind
|
||||
/// @param fmt information of the pixmap's visual
|
||||
/// @return backend specific image handle for the pixmap. May be
|
||||
/// NULL.
|
||||
image_handle (*bind_pixmap)(struct backend_base *backend_data, xcb_pixmap_t pixmap,
|
||||
struct xvisual_info fmt) __attribute__((nonnull(1)));
|
||||
|
||||
/// Acquire the image handle of the back buffer.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
image_handle (*back_buffer)(struct backend_base *backend_data);
|
||||
|
||||
/// Free resources associated with an image data structure. Releasing the image
|
||||
/// returned by `back_buffer` should be a no-op.
|
||||
///
|
||||
/// @param image the image to be released, cannot be NULL.
|
||||
/// @return if this image is created by `bind_pixmap`, the X pixmap; 0
|
||||
/// otherwise.
|
||||
xcb_pixmap_t (*release_image)(struct backend_base *backend_data, image_handle image)
|
||||
__attribute__((nonnull(1, 2)));
|
||||
|
||||
// =========== Query ===========
|
||||
|
||||
/// Get backend quirks
|
||||
/// @return a bitmask of `enum backend_quirk`.
|
||||
uint32_t (*quirks)(struct backend_base *backend_data) __attribute__((nonnull(1)));
|
||||
|
||||
/// Get the version of the backend
|
||||
void (*version)(struct backend_base *backend_data, uint64_t *major, uint64_t *minor)
|
||||
__attribute__((nonnull(1, 2, 3)));
|
||||
|
||||
/// Check if an optional image format is supported by the backend.
|
||||
bool (*is_format_supported)(struct backend_base *backend_data,
|
||||
enum backend_image_format format)
|
||||
__attribute__((nonnull(1)));
|
||||
|
||||
/// Return the capabilities of an image.
|
||||
uint32_t (*image_capabilities)(struct backend_base *backend_data, image_handle image)
|
||||
__attribute__((nonnull(1, 2)));
|
||||
|
||||
/// Get the attributes of a shader.
|
||||
///
|
||||
/// Optional, Returns a bitmask of attributes, see `shader_attributes`.
|
||||
uint64_t (*get_shader_attributes)(backend_t *backend_data, void *shader)
|
||||
__attribute__((nonnull(1, 2)));
|
||||
|
||||
/// Get the age of the buffer content we are currently rendering on top
|
||||
/// of. The buffer that has just been `present`ed has a buffer age of 1.
|
||||
/// Every time `present` is called, buffers get older. Return -1 if the
|
||||
/// buffer is empty.
|
||||
///
|
||||
/// 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 presented 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)(backend_t *backend_data);
|
||||
|
||||
// =========== Post-processing ============
|
||||
/// Create a blur context that can be used to call `blur` for images with a
|
||||
/// specific format.
|
||||
void *(*create_blur_context)(backend_t *base, enum blur_method,
|
||||
enum backend_image_format format, void *args);
|
||||
/// Destroy a blur context
|
||||
void (*destroy_blur_context)(backend_t *base, void *ctx);
|
||||
/// Get how many pixels outside of the blur area is needed for blur
|
||||
void (*get_blur_size)(void *blur_context, int *width, int *height);
|
||||
|
||||
// =========== Misc ============
|
||||
/// Return the driver that is been used by the backend
|
||||
enum driver (*detect_driver)(backend_t *backend_data);
|
||||
|
||||
void (*diagnostics)(backend_t *backend_data);
|
||||
|
||||
enum device_status (*device_status)(backend_t *backend_data);
|
||||
};
|
||||
|
||||
struct backend_base {
|
||||
struct backend_operations ops;
|
||||
struct x_connection *c;
|
||||
struct ev_loop *loop;
|
||||
|
||||
/// Whether the backend can accept new render request at the moment
|
||||
bool busy;
|
||||
// ...
|
||||
};
|
||||
|
||||
/// Register a new backend, `major` and `minor` should be the version of the picom backend
|
||||
/// interface. You should just pass `PICOM_BACKEND_MAJOR` and `PICOM_BACKEND_MINOR` here.
|
||||
/// `name` is the name of the backend, `init` is the function to initialize the backend,
|
||||
/// `can_present` should be true if the backend can present the back buffer to the screen,
|
||||
/// false otherwise (e.g. if the backend does off screen rendering, etc.)
|
||||
bool backend_register(uint64_t major, uint64_t minor, const char *name,
|
||||
struct backend_base *(*init)(session_t *ps, xcb_window_t target),
|
||||
bool can_present);
|
||||
|
||||
/// Define a backend entry point. (Note constructor priority 202 is used here because 1xx
|
||||
/// is reversed by test.h, and 201 is used for logging initialization.)
|
||||
#define BACKEND_ENTRYPOINT(func) static void __attribute__((constructor(202))) func(void)
|
8
include/picom/meson.build
Normal file
8
include/picom/meson.build
Normal file
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: MPL-2.0
|
||||
# Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||
|
||||
api_headers = [
|
||||
'api.h'
|
||||
'backend.h'
|
||||
]
|
||||
install_headers(api_headers, subdir: 'picom')
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
|
||||
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||
|
||||
#pragma once
|
||||
|
||||
|
@ -10,6 +10,15 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum blur_method {
|
||||
BLUR_METHOD_NONE = 0,
|
||||
BLUR_METHOD_KERNEL,
|
||||
BLUR_METHOD_BOX,
|
||||
BLUR_METHOD_GAUSSIAN,
|
||||
BLUR_METHOD_DUAL_KAWASE,
|
||||
BLUR_METHOD_INVALID,
|
||||
};
|
||||
|
||||
/// Enumeration type to represent switches.
|
||||
typedef enum {
|
||||
OFF = 0, // false
|
|
@ -76,6 +76,9 @@ OPTIONS
|
|||
*--write-pid-path* 'PATH'::
|
||||
Write process ID to a file. it is recommended to use an absolute path.
|
||||
|
||||
*--plugins* 'PATH'::
|
||||
Specify plugins to load. Plugins will first be searched in current working directory (unless specified in the config file, in which case this step is skipped), then in `$XDG_CONFIG_HOME/picom/plugins`, then in `$XDG_CONFIG_DIRS/picom/plugins`. If all of the above fail, the plugin name is passed directly to the dynamic loader. Can be specified multiple times to load more than one plugins.
|
||||
|
||||
*--shadow-color* 'STRING'::
|
||||
Color of shadow, as a hex string ('#000000')
|
||||
|
||||
|
|
|
@ -84,6 +84,15 @@ install_data('bin/picom-trans', install_dir: get_option('bindir'))
|
|||
install_data('picom.desktop', install_dir: 'share/applications')
|
||||
install_data('picom.desktop', install_dir: get_option('sysconfdir') / 'xdg' / 'autostart')
|
||||
|
||||
pkgconf = import('pkgconfig')
|
||||
|
||||
picom_pc = pkgconf.generate(
|
||||
name: 'picom-api',
|
||||
description: 'picom API headers',
|
||||
requires: [ 'pixman-1', 'xcb' ],
|
||||
subdirs: 'picom',
|
||||
)
|
||||
|
||||
if get_option('compton')
|
||||
install_data('compton.desktop', install_dir: 'share/applications')
|
||||
install_data('media/icons/48x48/compton.png',
|
||||
|
|
83
src/api.c
Normal file
83
src/api.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <picom/api.h>
|
||||
#include <picom/backend.h>
|
||||
|
||||
#include <uthash.h>
|
||||
|
||||
#include "compiler.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "utils.h"
|
||||
|
||||
struct backend_plugins {
|
||||
UT_hash_handle hh;
|
||||
const char *backend_name;
|
||||
struct list_node plugins;
|
||||
} *backend_plugins;
|
||||
|
||||
struct backend_plugin {
|
||||
const char *backend_name;
|
||||
picom_backend_plugin_entrypoint entrypoint;
|
||||
void *user_data;
|
||||
struct list_node siblings;
|
||||
};
|
||||
|
||||
static bool add_backend_plugin(const char *backend_name, uint64_t major, uint64_t minor,
|
||||
picom_backend_plugin_entrypoint entrypoint, void *user_data) {
|
||||
if (major != PICOM_BACKEND_MAJOR || minor > PICOM_BACKEND_MINOR) {
|
||||
log_error("Cannot add plugin for backend %s, because the requested "
|
||||
"version %" PRIu64 ".%" PRIu64 " is incompatible with the our "
|
||||
"%lu.%lu",
|
||||
backend_name, major, minor, PICOM_BACKEND_MAJOR,
|
||||
PICOM_BACKEND_MINOR);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto plugin = ccalloc(1, struct backend_plugin);
|
||||
plugin->backend_name = backend_name;
|
||||
plugin->entrypoint = entrypoint;
|
||||
plugin->user_data = user_data;
|
||||
|
||||
struct backend_plugins *plugins = NULL;
|
||||
HASH_FIND_STR(backend_plugins, backend_name, plugins);
|
||||
if (!plugins) {
|
||||
plugins = ccalloc(1, struct backend_plugins);
|
||||
plugins->backend_name = strdup(backend_name);
|
||||
list_init_head(&plugins->plugins);
|
||||
HASH_ADD_STR(backend_plugins, backend_name, plugins);
|
||||
}
|
||||
list_insert_after(&plugins->plugins, &plugin->siblings);
|
||||
return true;
|
||||
}
|
||||
|
||||
void api_backend_plugins_invoke(const char *backend_name, struct backend_base *backend) {
|
||||
struct backend_plugins *plugins = NULL;
|
||||
HASH_FIND_STR(backend_plugins, backend_name, plugins);
|
||||
if (!plugins) {
|
||||
return;
|
||||
}
|
||||
|
||||
list_foreach(struct backend_plugin, plugin, &plugins->plugins, siblings) {
|
||||
plugin->entrypoint(backend, plugin->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
static struct picom_api picom_api = {
|
||||
.add_backend_plugin = add_backend_plugin,
|
||||
};
|
||||
|
||||
PICOM_PUBLIC_API const struct picom_api *
|
||||
picom_api_get_interfaces(uint64_t major, uint64_t minor, const char *context) {
|
||||
if (major != PICOM_API_MAJOR || minor > PICOM_API_MINOR) {
|
||||
log_error("Cannot provide API interfaces to %s, because the requested"
|
||||
"version %" PRIu64 ".%" PRIu64 " is incompatible with our "
|
||||
"%lu.%lu",
|
||||
context, major, minor, PICOM_API_MAJOR, PICOM_API_MINOR);
|
||||
return NULL;
|
||||
}
|
||||
return &picom_api;
|
||||
}
|
7
src/api_internal.h
Normal file
7
src/api_internal.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||
|
||||
struct backend_base;
|
||||
|
||||
/// Invoke all backend plugins for the specified backend.
|
||||
void api_backend_plugins_invoke(const char *backend_name, struct backend_base *backend);
|
|
@ -1,32 +1,84 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||
#include <inttypes.h>
|
||||
#include <xcb/sync.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "backend/backend.h"
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "region.h"
|
||||
#include "types.h"
|
||||
#include "win.h"
|
||||
#include "x.h"
|
||||
|
||||
extern struct backend_operations xrender_ops, dummy_ops;
|
||||
#ifdef CONFIG_OPENGL
|
||||
extern struct backend_operations glx_ops;
|
||||
extern struct backend_operations egl_ops;
|
||||
#endif
|
||||
static struct backend_info {
|
||||
UT_hash_handle hh;
|
||||
const char *name;
|
||||
struct backend_base *(*init)(session_t *ps, xcb_window_t target);
|
||||
bool can_present;
|
||||
} *backend_registry = NULL;
|
||||
|
||||
struct backend_operations *backend_list[NUM_BKEND] = {
|
||||
[BKEND_XRENDER] = &xrender_ops,
|
||||
[BKEND_DUMMY] = &dummy_ops,
|
||||
#ifdef CONFIG_OPENGL
|
||||
[BKEND_GLX] = &glx_ops,
|
||||
[BKEND_EGL] = &egl_ops,
|
||||
#endif
|
||||
};
|
||||
PICOM_PUBLIC_API bool
|
||||
backend_register(uint64_t major, uint64_t minor, const char *name,
|
||||
struct backend_base *(*init)(session_t *ps, xcb_window_t target),
|
||||
bool can_present) {
|
||||
if (major != PICOM_BACKEND_MAJOR) {
|
||||
log_error("Backend %s has incompatible major version %" PRIu64
|
||||
", expected %lu",
|
||||
name, major, PICOM_BACKEND_MAJOR);
|
||||
return false;
|
||||
}
|
||||
if (minor > PICOM_BACKEND_MINOR) {
|
||||
log_error("Backend %s has incompatible minor version %" PRIu64
|
||||
", expected %lu",
|
||||
name, minor, PICOM_BACKEND_MINOR);
|
||||
return false;
|
||||
}
|
||||
struct backend_info *info = NULL;
|
||||
HASH_FIND_STR(backend_registry, name, info);
|
||||
if (info) {
|
||||
log_error("Backend %s is already registered", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
info = cmalloc(struct backend_info);
|
||||
info->name = name;
|
||||
info->init = init;
|
||||
info->can_present = can_present;
|
||||
HASH_ADD_KEYPTR(hh, backend_registry, info->name, strlen(info->name), info);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct backend_info *backend_find(const char *name) {
|
||||
struct backend_info *info = NULL;
|
||||
HASH_FIND_STR(backend_registry, name, info);
|
||||
return info;
|
||||
}
|
||||
|
||||
struct backend_base *
|
||||
backend_init(struct backend_info *info, session_t *ps, xcb_window_t target) {
|
||||
return info->init(ps, target);
|
||||
}
|
||||
|
||||
struct backend_info *backend_iter(void) {
|
||||
return backend_registry;
|
||||
}
|
||||
|
||||
struct backend_info *backend_iter_next(struct backend_info *info) {
|
||||
return info->hh.next;
|
||||
}
|
||||
|
||||
const char *backend_name(struct backend_info *info) {
|
||||
return info->name;
|
||||
}
|
||||
|
||||
bool backend_can_present(struct backend_info *info) {
|
||||
return info->can_present;
|
||||
}
|
||||
|
||||
void handle_device_reset(session_t *ps) {
|
||||
log_error("Device reset detected");
|
||||
|
@ -66,22 +118,22 @@ bool backend_execute(struct backend_base *backend, image_handle target, unsigned
|
|||
continue;
|
||||
}
|
||||
succeeded =
|
||||
backend->ops->blit(backend, cmd->origin, target, &cmd->blit);
|
||||
backend->ops.blit(backend, cmd->origin, target, &cmd->blit);
|
||||
break;
|
||||
case BACKEND_COMMAND_COPY_AREA:
|
||||
if (!pixman_region32_not_empty(cmd->copy_area.region)) {
|
||||
continue;
|
||||
}
|
||||
succeeded = backend->ops->copy_area(backend, cmd->origin, target,
|
||||
cmd->copy_area.source_image,
|
||||
cmd->copy_area.region);
|
||||
succeeded = backend->ops.copy_area(backend, cmd->origin, target,
|
||||
cmd->copy_area.source_image,
|
||||
cmd->copy_area.region);
|
||||
break;
|
||||
case BACKEND_COMMAND_BLUR:
|
||||
if (!pixman_region32_not_empty(cmd->blur.target_mask)) {
|
||||
continue;
|
||||
}
|
||||
succeeded =
|
||||
backend->ops->blur(backend, cmd->origin, target, &cmd->blur);
|
||||
backend->ops.blur(backend, cmd->origin, target, &cmd->blur);
|
||||
break;
|
||||
case BACKEND_COMMAND_INVALID:
|
||||
default: assert(false);
|
||||
|
|
|
@ -5,457 +5,25 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "driver.h"
|
||||
#include "kernel.h"
|
||||
#include "region.h"
|
||||
#include "types.h"
|
||||
#include "x.h"
|
||||
#include <picom/backend.h>
|
||||
|
||||
typedef struct session session_t;
|
||||
struct managed_win;
|
||||
|
||||
struct ev_loop;
|
||||
struct backend_operations;
|
||||
|
||||
typedef struct backend_base {
|
||||
struct backend_operations *ops;
|
||||
struct x_connection *c;
|
||||
struct ev_loop *loop;
|
||||
|
||||
/// Whether the backend can accept new render request at the moment
|
||||
bool busy;
|
||||
// ...
|
||||
} backend_t;
|
||||
|
||||
typedef void (*backend_ready_callback_t)(void *);
|
||||
|
||||
// This mimics OpenGL's ARB_robustness extension, which enables detection of GPU context
|
||||
// resets.
|
||||
// See: https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_robustness.txt, section
|
||||
// 2.6 "Graphics Reset Recovery".
|
||||
enum device_status {
|
||||
DEVICE_STATUS_NORMAL,
|
||||
DEVICE_STATUS_RESETTING,
|
||||
};
|
||||
|
||||
enum shader_attributes {
|
||||
// Whether the shader needs to be render regardless of whether the window is
|
||||
// updated.
|
||||
SHADER_ATTRIBUTE_ANIMATED = 1,
|
||||
};
|
||||
|
||||
struct gaussian_blur_args {
|
||||
int size;
|
||||
double deviation;
|
||||
};
|
||||
|
||||
struct box_blur_args {
|
||||
int size;
|
||||
};
|
||||
|
||||
struct kernel_blur_args {
|
||||
struct conv **kernels;
|
||||
int kernel_count;
|
||||
};
|
||||
|
||||
struct dual_kawase_blur_args {
|
||||
int size;
|
||||
int strength;
|
||||
};
|
||||
|
||||
typedef struct image_handle {
|
||||
// Intentionally left blank
|
||||
} *image_handle;
|
||||
|
||||
/// A mask for various backend operations.
|
||||
///
|
||||
/// The mask is composed of both a mask region and a mask image. The resulting mask
|
||||
/// is the intersection of the two. The mask image can be modified by the `corner_radius`
|
||||
/// and `inverted` properties. Note these properties have no effect on the mask region.
|
||||
struct backend_mask_image {
|
||||
/// Mask image, can be NULL.
|
||||
///
|
||||
/// Mask image must be an image that was created with the
|
||||
/// `BACKEND_IMAGE_FORMAT_MASK` format. Using an image with a wrong format as mask
|
||||
/// is undefined behavior.
|
||||
image_handle image;
|
||||
/// Corner radius of the mask image, the corners of the mask image will be
|
||||
/// rounded.
|
||||
double corner_radius;
|
||||
/// Origin of the mask image, in the source image's coordinate.
|
||||
ivec2 origin;
|
||||
/// Whether the mask image should be inverted.
|
||||
bool inverted;
|
||||
};
|
||||
|
||||
struct backend_blur_args {
|
||||
/// The blur context
|
||||
void *blur_context;
|
||||
/// The source mask for the blur operation, may be NULL. Only parts of the source
|
||||
/// image covered by the mask should participate in the blur operation.
|
||||
const struct backend_mask_image *source_mask;
|
||||
/// Region of the target image that will be covered by the blur operation, in the
|
||||
/// source image's coordinate.
|
||||
const region_t *target_mask;
|
||||
/// Source image
|
||||
image_handle source_image;
|
||||
/// Opacity of the blurred image
|
||||
double opacity;
|
||||
};
|
||||
|
||||
struct backend_blit_args {
|
||||
/// Source image, can be NULL.
|
||||
image_handle source_image;
|
||||
/// Mask for the source image. may be NULL. Only contents covered by the mask
|
||||
/// should participate in the blit operation. This applies to the source image
|
||||
/// before it's scaled.
|
||||
const struct backend_mask_image *source_mask;
|
||||
/// Mask for the target image. Only regions of the target image covered by this
|
||||
/// mask should be modified. This is the target's coordinate system.
|
||||
const region_t *target_mask;
|
||||
/// Custom shader for this blit operation.
|
||||
void *shader;
|
||||
/// Opacity of the source image.
|
||||
double opacity;
|
||||
/// Dim level of the source image.
|
||||
double dim;
|
||||
/// Brightness limit of the source image. Source image
|
||||
/// will be normalized so that the maximum brightness is
|
||||
/// this value.
|
||||
double max_brightness;
|
||||
/// Scale factor for the horizontal and vertical direction (X for horizontal,
|
||||
/// Y for vertical).
|
||||
vec2 scale;
|
||||
/// Corner radius of the source image BEFORE scaling. The corners of
|
||||
/// the source image will be rounded.
|
||||
double corner_radius;
|
||||
/// Effective size of the source image BEFORE scaling, set where the corners
|
||||
/// of the image are.
|
||||
ivec2 effective_size;
|
||||
/// Border width of the source image BEFORE scaling. This is used with
|
||||
/// `corner_radius` to create a border for the rounded corners.
|
||||
/// Setting this has no effect if `corner_radius` is 0.
|
||||
int border_width;
|
||||
/// Whether the source image should be inverted.
|
||||
bool color_inverted;
|
||||
};
|
||||
|
||||
enum backend_image_format {
|
||||
/// A format that can be used for normal rendering, and binding
|
||||
/// X pixmaps.
|
||||
/// Images created with `bind_pixmap` have this format automatically.
|
||||
BACKEND_IMAGE_FORMAT_PIXMAP,
|
||||
/// Like `BACKEND_IMAGE_FORMAT_PIXMAP`, but the image has a higher
|
||||
/// precision. Support is optional.
|
||||
BACKEND_IMAGE_FORMAT_PIXMAP_HIGH,
|
||||
/// A format that can be used for masks.
|
||||
BACKEND_IMAGE_FORMAT_MASK,
|
||||
};
|
||||
|
||||
enum backend_image_capability {
|
||||
/// Image can be sampled from. This is required for `blit` and `blur` source
|
||||
/// images. All images except the back buffer should have this capability.
|
||||
/// Note that `copy_area` should work without this capability, this is so that
|
||||
/// blurring the back buffer could be done.
|
||||
BACKEND_IMAGE_CAP_SRC = 1 << 0,
|
||||
/// Image can be rendered to. This is required for target images of any operation.
|
||||
/// All images except bound X pixmaps should have this capability.
|
||||
BACKEND_IMAGE_CAP_DST = 1 << 1,
|
||||
};
|
||||
|
||||
enum backend_command_op {
|
||||
BACKEND_COMMAND_INVALID = -1,
|
||||
BACKEND_COMMAND_BLIT,
|
||||
BACKEND_COMMAND_BLUR,
|
||||
BACKEND_COMMAND_COPY_AREA,
|
||||
};
|
||||
|
||||
/// Symbolic references used as render command source images. The actual `image_handle`
|
||||
/// will later be filled in by the renderer using this symbolic reference.
|
||||
enum backend_command_source {
|
||||
BACKEND_COMMAND_SOURCE_WINDOW,
|
||||
BACKEND_COMMAND_SOURCE_SHADOW,
|
||||
BACKEND_COMMAND_SOURCE_BACKGROUND,
|
||||
};
|
||||
|
||||
// TODO(yshui) might need better names
|
||||
|
||||
struct backend_command {
|
||||
enum backend_command_op op;
|
||||
ivec2 origin;
|
||||
enum backend_command_source source;
|
||||
union {
|
||||
struct {
|
||||
struct backend_blit_args blit;
|
||||
/// Region of the screen that will be covered by this blit
|
||||
/// operations, in screen coordinates.
|
||||
region_t opaque_region;
|
||||
};
|
||||
struct {
|
||||
image_handle source_image;
|
||||
const region_t *region;
|
||||
} copy_area;
|
||||
struct backend_blur_args blur;
|
||||
};
|
||||
/// Source mask for the operation.
|
||||
/// If the `source_mask` of the operation's argument points to this, a mask image
|
||||
/// will be created for the operation for the renderer.
|
||||
struct backend_mask_image source_mask;
|
||||
/// Target mask for the operation.
|
||||
region_t target_mask;
|
||||
};
|
||||
|
||||
enum backend_quirk {
|
||||
/// Backend cannot do blur quickly. The compositor will avoid using blur to create
|
||||
/// shadows on this backend
|
||||
BACKEND_QUIRK_SLOW_BLUR = 1 << 0,
|
||||
};
|
||||
|
||||
struct backend_operations {
|
||||
// =========== Initialization ===========
|
||||
|
||||
/// Initialize the backend, prepare for rendering to the target window.
|
||||
backend_t *(*init)(session_t *, xcb_window_t)attr_nonnull(1);
|
||||
void (*deinit)(backend_t *backend_data) attr_nonnull(1);
|
||||
|
||||
/// Called when rendering will be stopped for an unknown amount of
|
||||
/// time (e.g. when screen is unredirected). Free some resources.
|
||||
///
|
||||
/// Optional, not yet used
|
||||
void (*pause)(backend_t *backend_data, session_t *ps);
|
||||
|
||||
/// Called before rendering is resumed
|
||||
///
|
||||
/// Optional, not yet used
|
||||
void (*resume)(backend_t *backend_data, session_t *ps);
|
||||
|
||||
/// Called when root window size changed. All existing image data ever
|
||||
/// returned by this backend should remain valid after this call
|
||||
/// returns.
|
||||
///
|
||||
/// Optional
|
||||
void (*root_change)(backend_t *backend_data, session_t *ps);
|
||||
|
||||
// =========== Rendering ============
|
||||
|
||||
/// Called before when a new frame starts.
|
||||
///
|
||||
/// Optional
|
||||
void (*prepare)(backend_t *backend_data, const region_t *reg_damage);
|
||||
|
||||
/// Multiply the alpha channel of the target image by a given value.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param target an image handle, cannot be NULL.
|
||||
/// @param alpha the alpha value to multiply
|
||||
/// @param region the region to apply the alpha, in the target image's
|
||||
/// coordinate.
|
||||
bool (*apply_alpha)(struct backend_base *backend_data, image_handle target,
|
||||
double alpha, const region_t *region) attr_nonnull(1, 2, 4);
|
||||
|
||||
/// Copy pixels from a source image on to the target image.
|
||||
///
|
||||
/// Some effects may be applied. If the region specified by the mask
|
||||
/// contains parts that are outside the source image, the source image
|
||||
/// will be repeated to fit.
|
||||
///
|
||||
/// Source and target MUST NOT be the same image.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param origin the origin of the operation, in the target image's
|
||||
/// coordinate.
|
||||
/// @param target an image handle, cannot be NULL.
|
||||
/// @param args arguments for blit
|
||||
/// @return whether the operation is successful
|
||||
bool (*blit)(struct backend_base *backend_data, ivec2 origin, image_handle target,
|
||||
const struct backend_blit_args *args) attr_nonnull(1, 3, 4);
|
||||
|
||||
/// Blur a given region of a source image and store the result in the
|
||||
/// target image.
|
||||
///
|
||||
/// The blur operation might access pixels outside the mask region, the
|
||||
/// amount of pixels accessed can be queried with `get_blur_size`. If
|
||||
/// pixels outside the source image are accessed, the result will be
|
||||
/// clamped to the edge of the source image.
|
||||
///
|
||||
/// Source and target may be the same image.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param origin the origin of the operation, in the target image's
|
||||
/// coordinate.
|
||||
/// @param target an image handle, cannot be NULL.
|
||||
/// @param args argument for blur
|
||||
/// @return whether the operation is successful
|
||||
bool (*blur)(struct backend_base *backend_data, ivec2 origin, image_handle target,
|
||||
const struct backend_blur_args *args) attr_nonnull(1, 3, 4);
|
||||
|
||||
/// Direct copy of pixels from a source image on to the target image.
|
||||
/// This is a simpler version of `blit`, without any effects. Note unlike `blit`,
|
||||
/// if `region` tries to sample from outside the source image, instead of
|
||||
/// repeating, the result will be clamped to the edge of the source image.
|
||||
/// Blending should not be applied for the copy.
|
||||
///
|
||||
/// Source and target MUST NOT be the same image.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param origin the origin of the operation, in the target image's
|
||||
/// coordinate.
|
||||
/// @param target an image handle, cannot be NULL.
|
||||
/// @param source an image handle, cannot be NULL.
|
||||
/// @param region the region to copy, in the target image's coordinate.
|
||||
/// @return whether the operation is successful
|
||||
bool (*copy_area)(struct backend_base *backend_data, ivec2 origin,
|
||||
image_handle target, image_handle source, const region_t *region)
|
||||
attr_nonnull(1, 3, 4, 5);
|
||||
|
||||
/// Similar to `copy_area`, but is specialized for copying from a higher
|
||||
/// precision format to a lower precision format. It has 2 major differences from
|
||||
/// `copy_area`:
|
||||
///
|
||||
/// 1. This function _may_ use dithering when copying from a higher precision
|
||||
/// format to a lower precision format. But this is not required.
|
||||
/// 2. This function only needs to support copying from an image with the SRC
|
||||
/// capability. Unlike `copy_area`, which supports copying from any image.
|
||||
///
|
||||
/// It's perfectly legal to have this pointing to the same function as
|
||||
/// `copy_area`, if the backend doesn't support dithering.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param origin the origin of the operation, in the target image's
|
||||
/// coordinate.
|
||||
/// @param target an image handle, cannot be NULL.
|
||||
/// @param source an image handle, cannot be NULL.
|
||||
/// @param region the region to copy, in the target image's coordinate.
|
||||
/// @return whether the operation is successful
|
||||
bool (*copy_area_quantize)(struct backend_base *backend_data, ivec2 origin,
|
||||
image_handle target, image_handle source,
|
||||
const region_t *region) attr_nonnull(1, 3, 4, 5);
|
||||
|
||||
/// Initialize an image with a given color value. If the image has a mask format,
|
||||
/// only the alpha channel of the color is used.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param target an image handle, cannot be NULL.
|
||||
/// @param color the color to fill the image with
|
||||
/// @return whether the operation is successful
|
||||
bool (*clear)(struct backend_base *backend_data, image_handle target,
|
||||
struct color color) attr_nonnull(1, 2);
|
||||
|
||||
/// Present the back buffer to the target window. Ideally the backend should keep
|
||||
/// track of the region of the back buffer that has been updated, and use relevant
|
||||
/// mechanism (when possible) to present only the updated region.
|
||||
bool (*present)(struct backend_base *backend_data) attr_nonnull(1);
|
||||
|
||||
// ============ Resource management ===========
|
||||
|
||||
/// Create a shader object from a shader source.
|
||||
///
|
||||
/// Optional
|
||||
void *(*create_shader)(backend_t *backend_data, const char *source)attr_nonnull(1, 2);
|
||||
|
||||
/// Free a shader object.
|
||||
///
|
||||
/// Required if create_shader is present.
|
||||
void (*destroy_shader)(backend_t *backend_data, void *shader) attr_nonnull(1, 2);
|
||||
|
||||
/// Create a new, uninitialized image with the given format and size.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param format the format of the image
|
||||
/// @param size the size of the image
|
||||
image_handle (*new_image)(struct backend_base *backend_data,
|
||||
enum backend_image_format format, ivec2 size)
|
||||
attr_nonnull(1);
|
||||
|
||||
/// Bind a X pixmap to the backend's internal image data structure.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
/// @param pixmap X pixmap to bind
|
||||
/// @param fmt information of the pixmap's visual
|
||||
/// @return backend specific image handle for the pixmap. May be
|
||||
/// NULL.
|
||||
image_handle (*bind_pixmap)(struct backend_base *backend_data, xcb_pixmap_t pixmap,
|
||||
struct xvisual_info fmt) attr_nonnull(1);
|
||||
|
||||
/// Acquire the image handle of the back buffer.
|
||||
///
|
||||
/// @param backend_data backend data
|
||||
image_handle (*back_buffer)(struct backend_base *backend_data);
|
||||
|
||||
/// Free resources associated with an image data structure. Releasing the image
|
||||
/// returned by `back_buffer` should be a no-op.
|
||||
///
|
||||
/// @param image the image to be released, cannot be NULL.
|
||||
/// @return if this image is created by `bind_pixmap`, the X pixmap; 0
|
||||
/// otherwise.
|
||||
xcb_pixmap_t (*release_image)(struct backend_base *backend_data, image_handle image)
|
||||
attr_nonnull(1, 2);
|
||||
|
||||
// =========== Query ===========
|
||||
|
||||
/// Get backend quirks
|
||||
/// @return a bitmask of `enum backend_quirk`.
|
||||
uint32_t (*quirks)(struct backend_base *backend_data) attr_nonnull(1);
|
||||
|
||||
/// Check if an optional image format is supported by the backend.
|
||||
bool (*is_format_supported)(struct backend_base *backend_data,
|
||||
enum backend_image_format format) attr_nonnull(1);
|
||||
|
||||
/// Return the capabilities of an image.
|
||||
uint32_t (*image_capabilities)(struct backend_base *backend_data, image_handle image)
|
||||
attr_nonnull(1, 2);
|
||||
|
||||
/// Get the attributes of a shader.
|
||||
///
|
||||
/// Optional, Returns a bitmask of attributes, see `shader_attributes`.
|
||||
uint64_t (*get_shader_attributes)(backend_t *backend_data, void *shader)
|
||||
attr_nonnull(1, 2);
|
||||
|
||||
/// Get the age of the buffer content we are currently rendering on top
|
||||
/// of. The buffer that has just been `present`ed has a buffer age of 1.
|
||||
/// Every time `present` is called, buffers get older. Return -1 if the
|
||||
/// buffer is empty.
|
||||
///
|
||||
/// 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 presented 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;
|
||||
|
||||
// =========== Post-processing ============
|
||||
/// Create a blur context that can be used to call `blur` for images with a
|
||||
/// specific format.
|
||||
void *(*create_blur_context)(backend_t *base, enum blur_method,
|
||||
enum backend_image_format format, void *args);
|
||||
/// Destroy a blur context
|
||||
void (*destroy_blur_context)(backend_t *base, void *ctx);
|
||||
/// Get how many pixels outside of the blur area is needed for blur
|
||||
void (*get_blur_size)(void *blur_context, int *width, int *height);
|
||||
|
||||
// =========== Misc ============
|
||||
/// Return the driver that is been used by the backend
|
||||
enum driver (*detect_driver)(backend_t *backend_data);
|
||||
|
||||
void (*diagnostics)(backend_t *backend_data);
|
||||
|
||||
enum device_status (*device_status)(backend_t *backend_data);
|
||||
};
|
||||
|
||||
extern struct backend_operations *backend_list[];
|
||||
#include "log.h"
|
||||
|
||||
bool backend_execute(struct backend_base *backend, image_handle target, unsigned ncmds,
|
||||
const struct backend_command cmds[ncmds]);
|
||||
|
||||
struct backend_info *backend_find(const char *name);
|
||||
struct backend_base *
|
||||
backend_init(struct backend_info *info, session_t *ps, xcb_window_t target);
|
||||
struct backend_info *backend_iter(void);
|
||||
struct backend_info *backend_iter_next(struct backend_info *info);
|
||||
const char *backend_name(struct backend_info *info);
|
||||
bool backend_can_present(struct backend_info *info);
|
||||
void log_backend_command_(enum log_level level, const char *func,
|
||||
const struct backend_command *cmd);
|
||||
#define log_backend_command(level, cmd) \
|
||||
log_backend_command_(LOG_LEVEL_##level, __func__, &(cmd));
|
||||
|
||||
/// Define a backend entry point. (Note constructor priority 202 is used here because 1xx
|
||||
/// is reversed by test.h, and 201 is used for logging initialization.)
|
||||
#define BACKEND_ENTRYPOINT(func) static void __attribute__((constructor(202))) func(void)
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include <xcb/xcb_image.h>
|
||||
#include <xcb/xcb_renderutil.h>
|
||||
|
||||
#include "backend/backend.h"
|
||||
#include "backend/backend_common.h"
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
|
@ -413,7 +412,7 @@ void init_backend_base(struct backend_base *base, session_t *ps) {
|
|||
base->c = &ps->c;
|
||||
base->loop = ps->loop;
|
||||
base->busy = false;
|
||||
base->ops = NULL;
|
||||
base->ops = (struct backend_operations){};
|
||||
}
|
||||
|
||||
uint32_t backend_no_quirks(struct backend_base *base attr_unused) {
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "backend.h"
|
||||
#include "config.h"
|
||||
#include "region.h"
|
||||
|
||||
struct session;
|
||||
struct win;
|
||||
struct conv;
|
||||
struct backend_base;
|
||||
struct backend_operations;
|
||||
struct x_connection;
|
||||
|
||||
struct dual_kawase_params {
|
||||
/// Number of downsample passes
|
||||
|
|
|
@ -83,8 +83,8 @@ enum driver detect_driver(xcb_connection_t *c, backend_t *backend_data, xcb_wind
|
|||
free(randr_version);
|
||||
|
||||
// If the backend supports driver detection, use that as well
|
||||
if (backend_data && backend_data->ops->detect_driver) {
|
||||
ret |= backend_data->ops->detect_driver(backend_data);
|
||||
if (backend_data && backend_data->ops.detect_driver) {
|
||||
ret |= backend_data->ops.detect_driver(backend_data);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include <uthash.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "backend/backend.h"
|
||||
#include "backend/backend_common.h"
|
||||
#include "common.h"
|
||||
|
@ -8,7 +10,6 @@
|
|||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "region.h"
|
||||
#include "types.h"
|
||||
#include "uthash_extra.h"
|
||||
#include "utils.h"
|
||||
#include "x.h"
|
||||
|
@ -28,12 +29,12 @@ struct dummy_data {
|
|||
struct dummy_image back_buffer;
|
||||
};
|
||||
|
||||
struct backend_operations dummy_ops;
|
||||
const struct backend_operations dummy_ops;
|
||||
|
||||
struct backend_base *dummy_init(session_t *ps attr_unused, xcb_window_t target attr_unused) {
|
||||
auto ret = ccalloc(1, struct dummy_data);
|
||||
init_backend_base(&ret->base, ps);
|
||||
ret->base.ops = &dummy_ops;
|
||||
ret->base.ops = dummy_ops;
|
||||
list_init_head(&ret->non_pixmap_images);
|
||||
return &ret->base;
|
||||
}
|
||||
|
@ -203,7 +204,19 @@ bool dummy_is_format_supported(struct backend_base *base attr_unused,
|
|||
return true;
|
||||
}
|
||||
|
||||
struct backend_operations dummy_ops = {
|
||||
static int dummy_max_buffer_age(struct backend_base *base attr_unused) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
#define PICOM_BACKEND_DUMMY_MAJOR (0UL)
|
||||
#define PICOM_BACKEND_DUMMY_MINOR (1UL)
|
||||
|
||||
static void dummy_version(struct backend_base * /*base*/, uint64_t *major, uint64_t *minor) {
|
||||
*major = PICOM_BACKEND_DUMMY_MAJOR;
|
||||
*minor = PICOM_BACKEND_DUMMY_MINOR;
|
||||
}
|
||||
|
||||
const struct backend_operations dummy_ops = {
|
||||
.apply_alpha = dummy_apply_alpha,
|
||||
.back_buffer = dummy_back_buffer,
|
||||
.blit = dummy_blit,
|
||||
|
@ -216,14 +229,22 @@ struct backend_operations dummy_ops = {
|
|||
.new_image = dummy_new_image,
|
||||
.bind_pixmap = dummy_bind_pixmap,
|
||||
.quirks = backend_no_quirks,
|
||||
.version = dummy_version,
|
||||
.release_image = dummy_release_image,
|
||||
|
||||
.init = dummy_init,
|
||||
.deinit = dummy_deinit,
|
||||
.buffer_age = dummy_buffer_age,
|
||||
.max_buffer_age = 5,
|
||||
.max_buffer_age = dummy_max_buffer_age,
|
||||
|
||||
.create_blur_context = dummy_create_blur_context,
|
||||
.destroy_blur_context = dummy_destroy_blur_context,
|
||||
.get_blur_size = dummy_get_blur_size,
|
||||
};
|
||||
|
||||
BACKEND_ENTRYPOINT(dummy_register) {
|
||||
if (!backend_register(PICOM_BACKEND_MAJOR, PICOM_BACKEND_MINOR, "dummy",
|
||||
dummy_ops.init, false)) {
|
||||
log_error("Failed to register dummy backend");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
*/
|
||||
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -76,10 +74,9 @@ static void egl_release_image(backend_t *base, struct gl_texture *tex) {
|
|||
void egl_deinit(backend_t *base) {
|
||||
struct egl_data *gd = (void *)base;
|
||||
|
||||
gl_deinit(&gd->gl);
|
||||
|
||||
// Destroy EGL context
|
||||
if (gd->ctx != EGL_NO_CONTEXT) {
|
||||
gl_deinit(&gd->gl);
|
||||
eglMakeCurrent(gd->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
eglDestroyContext(gd->display, gd->ctx);
|
||||
gd->ctx = EGL_NO_CONTEXT;
|
||||
|
@ -106,7 +103,7 @@ static bool egl_set_swap_interval(int interval, EGLDisplay dpy) {
|
|||
return eglSwapInterval(dpy, interval);
|
||||
}
|
||||
|
||||
struct backend_operations egl_ops;
|
||||
const struct backend_operations egl_ops;
|
||||
/**
|
||||
* Initialize OpenGL.
|
||||
*/
|
||||
|
@ -121,6 +118,8 @@ static backend_t *egl_init(session_t *ps, xcb_window_t target) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
log_warn("The egl backend is still experimental, use with care.");
|
||||
|
||||
gd = ccalloc(1, struct egl_data);
|
||||
gd->display = eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, ps->c.dpy,
|
||||
(EGLint[]){
|
||||
|
@ -153,7 +152,7 @@ static backend_t *egl_init(session_t *ps, xcb_window_t target) {
|
|||
|
||||
eglext_init(gd->display);
|
||||
init_backend_base(&gd->gl.base, ps);
|
||||
gd->gl.base.ops = &egl_ops;
|
||||
gd->gl.base.ops = egl_ops;
|
||||
if (!eglext.has_EGL_KHR_image_pixmap) {
|
||||
log_error("EGL_KHR_image_pixmap not available.");
|
||||
goto end;
|
||||
|
@ -338,7 +337,23 @@ static void egl_diagnostics(backend_t *base) {
|
|||
}
|
||||
}
|
||||
|
||||
struct backend_operations egl_ops = {
|
||||
static int egl_max_buffer_age(backend_t *base attr_unused) {
|
||||
if (!eglext.has_EGL_EXT_buffer_age) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 5; // Why?
|
||||
}
|
||||
|
||||
#define PICOM_BACKEND_EGL_MAJOR (0UL)
|
||||
#define PICOM_BACKEND_EGL_MINOR (1UL)
|
||||
|
||||
static void egl_version(struct backend_base * /*base*/, uint64_t *major, uint64_t *minor) {
|
||||
*major = PICOM_BACKEND_EGL_MAJOR;
|
||||
*minor = PICOM_BACKEND_EGL_MINOR;
|
||||
}
|
||||
|
||||
const struct backend_operations egl_ops = {
|
||||
.apply_alpha = gl_apply_alpha,
|
||||
.back_buffer = gl_back_buffer,
|
||||
.blit = gl_blit,
|
||||
|
@ -352,6 +367,7 @@ struct backend_operations egl_ops = {
|
|||
.new_image = gl_new_image,
|
||||
.present = egl_present,
|
||||
.quirks = backend_no_quirks,
|
||||
.version = egl_version,
|
||||
.release_image = gl_release_image,
|
||||
|
||||
.init = egl_init,
|
||||
|
@ -368,7 +384,7 @@ struct backend_operations egl_ops = {
|
|||
.create_shader = gl_create_window_shader,
|
||||
.destroy_shader = gl_destroy_window_shader,
|
||||
.get_shader_attributes = gl_get_shader_attributes,
|
||||
.max_buffer_age = 5, // Why?
|
||||
.max_buffer_age = egl_max_buffer_age,
|
||||
};
|
||||
|
||||
struct eglext_info eglext = {0};
|
||||
|
@ -390,3 +406,10 @@ void eglext_init(EGLDisplay dpy) {
|
|||
#endif
|
||||
#undef check_ext
|
||||
}
|
||||
|
||||
BACKEND_ENTRYPOINT(egl_register) {
|
||||
if (!backend_register(PICOM_BACKEND_MAJOR, PICOM_BACKEND_MINOR, "egl",
|
||||
egl_ops.init, true)) {
|
||||
log_error("Failed to register egl backend");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
#include <time.h>
|
||||
#include <xcb/render.h> // for xcb_render_fixed_t, XXX
|
||||
|
||||
#include "backend/backend.h"
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "region.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "backend/backend_common.h"
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
*/
|
||||
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <pixman.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -31,7 +30,6 @@
|
|||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "picom.h"
|
||||
#include "region.h"
|
||||
#include "utils.h"
|
||||
#include "win.h"
|
||||
#include "x.h"
|
||||
|
@ -225,7 +223,7 @@ static bool glx_set_swap_interval(int interval, Display *dpy, GLXDrawable drawab
|
|||
return vsync_enabled;
|
||||
}
|
||||
|
||||
struct backend_operations glx_ops;
|
||||
const struct backend_operations glx_ops;
|
||||
/**
|
||||
* Initialize OpenGL.
|
||||
*/
|
||||
|
@ -234,7 +232,7 @@ static backend_t *glx_init(session_t *ps, xcb_window_t target) {
|
|||
glxext_init(ps->c.dpy, ps->c.screen);
|
||||
auto gd = ccalloc(1, struct _glx_data);
|
||||
init_backend_base(&gd->gl.base, ps);
|
||||
gd->gl.base.ops = &glx_ops;
|
||||
gd->gl.base.ops = glx_ops;
|
||||
|
||||
gd->target_win = target;
|
||||
|
||||
|
@ -517,7 +515,19 @@ static void glx_diagnostics(backend_t *base) {
|
|||
}
|
||||
}
|
||||
|
||||
struct backend_operations glx_ops = {
|
||||
static int glx_max_buffer_age(struct backend_base *base attr_unused) {
|
||||
return 5; // Why?
|
||||
}
|
||||
|
||||
#define PICOM_BACKEND_GLX_MAJOR (0UL)
|
||||
#define PICOM_BACKEND_GLX_MINOR (1UL)
|
||||
|
||||
static void glx_version(struct backend_base * /*base*/, uint64_t *major, uint64_t *minor) {
|
||||
*major = PICOM_BACKEND_GLX_MAJOR;
|
||||
*minor = PICOM_BACKEND_GLX_MINOR;
|
||||
}
|
||||
|
||||
const struct backend_operations glx_ops = {
|
||||
.apply_alpha = gl_apply_alpha,
|
||||
.back_buffer = gl_back_buffer,
|
||||
.bind_pixmap = glx_bind_pixmap,
|
||||
|
@ -531,6 +541,7 @@ struct backend_operations glx_ops = {
|
|||
.new_image = gl_new_image,
|
||||
.present = glx_present,
|
||||
.quirks = backend_no_quirks,
|
||||
.version = glx_version,
|
||||
.release_image = gl_release_image,
|
||||
|
||||
.init = glx_init,
|
||||
|
@ -547,7 +558,7 @@ struct backend_operations glx_ops = {
|
|||
.create_shader = gl_create_window_shader,
|
||||
.destroy_shader = gl_destroy_window_shader,
|
||||
.get_shader_attributes = gl_get_shader_attributes,
|
||||
.max_buffer_age = 5, // Why?
|
||||
.max_buffer_age = glx_max_buffer_age,
|
||||
};
|
||||
|
||||
struct glxext_info glxext = {0};
|
||||
|
@ -575,3 +586,10 @@ void glxext_init(Display *dpy, int screen) {
|
|||
#endif
|
||||
#undef check_ext
|
||||
}
|
||||
|
||||
BACKEND_ENTRYPOINT(glx_register) {
|
||||
if (!backend_register(PICOM_BACKEND_MAJOR, PICOM_BACKEND_MINOR, "glx",
|
||||
glx_ops.init, true)) {
|
||||
log_error("Failed to register glx backend");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <xcb/sync.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "backend/backend.h"
|
||||
#include "backend/backend_common.h"
|
||||
#include "backend/driver.h"
|
||||
|
@ -22,7 +24,6 @@
|
|||
#include "log.h"
|
||||
#include "picom.h"
|
||||
#include "region.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "win.h"
|
||||
#include "x.h"
|
||||
|
@ -864,15 +865,20 @@ static void xrender_get_blur_size(void *blur_context, int *width, int *height) {
|
|||
*width = ctx->resize_width;
|
||||
*height = ctx->resize_height;
|
||||
}
|
||||
struct backend_operations xrender_ops;
|
||||
const struct backend_operations xrender_ops;
|
||||
static backend_t *xrender_init(session_t *ps, xcb_window_t target) {
|
||||
if (ps->o.dithered_present) {
|
||||
log_warn("\"dithered-present\" is not supported by the xrender backend.");
|
||||
log_warn("\"dithered-present\" is not supported by the xrender backend, "
|
||||
"it will be ignored.");
|
||||
}
|
||||
if (ps->o.max_brightness < 1.0) {
|
||||
log_warn("\"max-brightness\" is not supported by the xrender backend, it "
|
||||
"will be ignored.");
|
||||
}
|
||||
|
||||
auto xd = ccalloc(1, struct xrender_data);
|
||||
init_backend_base(&xd->base, ps);
|
||||
xd->base.ops = &xrender_ops;
|
||||
xd->base.ops = xrender_ops;
|
||||
|
||||
for (int i = 0; i <= MAX_ALPHA; ++i) {
|
||||
double o = (double)i / (double)MAX_ALPHA;
|
||||
|
@ -1014,7 +1020,19 @@ uint32_t xrender_quirks(struct backend_base *base) {
|
|||
return ((struct xrender_data *)base)->quirks;
|
||||
}
|
||||
|
||||
struct backend_operations xrender_ops = {
|
||||
static int xrender_max_buffer_age(struct backend_base *base) {
|
||||
return ((struct xrender_data *)base)->vsync ? 2 : 1;
|
||||
}
|
||||
|
||||
#define PICOM_BACKEND_XRENDER_MAJOR (0UL)
|
||||
#define PICOM_BACKEND_XRENDER_MINOR (1UL)
|
||||
|
||||
static void xrender_version(struct backend_base * /*base*/, uint64_t *major, uint64_t *minor) {
|
||||
*major = PICOM_BACKEND_XRENDER_MAJOR;
|
||||
*minor = PICOM_BACKEND_XRENDER_MINOR;
|
||||
}
|
||||
|
||||
const struct backend_operations xrender_ops = {
|
||||
.apply_alpha = xrender_apply_alpha,
|
||||
.back_buffer = xrender_back_buffer,
|
||||
.bind_pixmap = xrender_bind_pixmap,
|
||||
|
@ -1028,6 +1046,7 @@ struct backend_operations xrender_ops = {
|
|||
.new_image = xrender_new_image,
|
||||
.present = xrender_present,
|
||||
.quirks = xrender_quirks,
|
||||
.version = xrender_version,
|
||||
.release_image = xrender_release_image,
|
||||
|
||||
.init = xrender_init,
|
||||
|
@ -1036,11 +1055,18 @@ struct backend_operations xrender_ops = {
|
|||
// `render_shadow`, and `backend_compat_shadow_from_mask` for
|
||||
// `shadow_from_mask`
|
||||
.buffer_age = xrender_buffer_age,
|
||||
.max_buffer_age = 2,
|
||||
.max_buffer_age = xrender_max_buffer_age,
|
||||
.create_blur_context = xrender_create_blur_context,
|
||||
.destroy_blur_context = xrender_destroy_blur_context,
|
||||
.get_blur_size = xrender_get_blur_size
|
||||
// end
|
||||
};
|
||||
|
||||
BACKEND_ENTRYPOINT(xrender_register) {
|
||||
if (!backend_register(PICOM_BACKEND_MAJOR, PICOM_BACKEND_MINOR, "xrender",
|
||||
xrender_ops.init, true)) {
|
||||
log_error("Failed to register xrender backend");
|
||||
}
|
||||
}
|
||||
|
||||
// vim: set noet sw=8 ts=8:
|
||||
|
|
1
src/c2.c
1
src/c2.c
|
@ -36,6 +36,7 @@
|
|||
#include "log.h"
|
||||
#include "string_utils.h"
|
||||
#include "test.h"
|
||||
#include "uthash_extra.h"
|
||||
#include "utils.h"
|
||||
#include "win.h"
|
||||
#include "x.h"
|
||||
|
|
11
src/common.h
11
src/common.h
|
@ -40,7 +40,9 @@
|
|||
#include <xcb/sync.h>
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
#include "uthash_extra.h"
|
||||
#include <picom/backend.h>
|
||||
#include <picom/types.h>
|
||||
|
||||
#ifdef CONFIG_OPENGL
|
||||
#include "backend/gl/glx.h"
|
||||
#endif
|
||||
|
@ -51,16 +53,11 @@
|
|||
#endif
|
||||
|
||||
// FIXME This list of includes should get shorter
|
||||
#include "backend/backend.h"
|
||||
#include "backend/driver.h"
|
||||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "list.h"
|
||||
#include "region.h"
|
||||
#include "render.h"
|
||||
#include "statistics.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "win_defs.h"
|
||||
#include "x.h"
|
||||
|
||||
|
@ -462,7 +459,7 @@ static inline xcb_window_t get_tgt_window(session_t *ps) {
|
|||
* Check if current backend uses GLX.
|
||||
*/
|
||||
static inline bool bkend_use_glx(session_t *ps) {
|
||||
return BKEND_GLX == ps->o.backend || BKEND_XR_GLX_HYBRID == ps->o.backend;
|
||||
return BKEND_GLX == ps->o.legacy_backend || BKEND_XR_GLX_HYBRID == ps->o.legacy_backend;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -126,6 +126,8 @@
|
|||
#else
|
||||
# define thread_local _Pragma("GCC error \"No thread local storage support\"") __error__
|
||||
#endif
|
||||
|
||||
#define PICOM_PUBLIC_API __attribute__((visibility("default")))
|
||||
// clang-format on
|
||||
|
||||
typedef unsigned long ulong;
|
||||
|
|
27
src/config.c
27
src/config.c
|
@ -3,13 +3,11 @@
|
|||
// Copyright (c) 2013 Richard Grenville <pyxlcy@gmail.com>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -18,18 +16,13 @@
|
|||
#include <unistd.h>
|
||||
#include <xcb/render.h> // for xcb_render_fixed_t, XXX
|
||||
|
||||
#include <picom/types.h>
|
||||
#include <test.h>
|
||||
|
||||
#include "c2.h"
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
#include "kernel.h"
|
||||
#include "log.h"
|
||||
#include "region.h"
|
||||
#include "string_utils.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "win.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
@ -632,11 +625,23 @@ void *parse_window_shader_prefix_with_cwd(const char *src, const char **end, voi
|
|||
return parse_window_shader_prefix(src, end, cwd);
|
||||
}
|
||||
|
||||
bool load_plugin(const char *name, const char *include_dir) {
|
||||
scoped_charp path = locate_auxiliary_file("plugins", optarg, include_dir);
|
||||
void *handle = NULL;
|
||||
if (!path) {
|
||||
handle = dlopen(name, RTLD_LAZY);
|
||||
} else {
|
||||
log_debug("Plugin %s resolved to %s", name, path);
|
||||
handle = dlopen(path, RTLD_LAZY);
|
||||
}
|
||||
return handle != NULL;
|
||||
}
|
||||
|
||||
bool parse_config(options_t *opt, const char *config_file) {
|
||||
// clang-format off
|
||||
*opt = (struct options){
|
||||
.backend = BKEND_XRENDER,
|
||||
.legacy_backends = false,
|
||||
.legacy_backend = BKEND_XRENDER,
|
||||
.use_legacy_backends = false,
|
||||
.glx_no_stencil = false,
|
||||
.mark_wmwin_focused = false,
|
||||
.mark_ovredir_focused = false,
|
||||
|
|
22
src/config.h
22
src/config.h
|
@ -16,12 +16,12 @@
|
|||
#include <xcb/xfixes.h>
|
||||
|
||||
#include <libconfig.h>
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "compiler.h"
|
||||
#include "kernel.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "types.h"
|
||||
#include "win_defs.h"
|
||||
|
||||
typedef struct session session_t;
|
||||
|
@ -58,15 +58,6 @@ typedef struct win_option {
|
|||
bool clip_shadow_above;
|
||||
} win_option_t;
|
||||
|
||||
enum blur_method {
|
||||
BLUR_METHOD_NONE = 0,
|
||||
BLUR_METHOD_KERNEL,
|
||||
BLUR_METHOD_BOX,
|
||||
BLUR_METHOD_GAUSSIAN,
|
||||
BLUR_METHOD_DUAL_KAWASE,
|
||||
BLUR_METHOD_INVALID,
|
||||
};
|
||||
|
||||
typedef struct _c2_lptr c2_lptr_t;
|
||||
|
||||
enum vblank_scheduler_type {
|
||||
|
@ -158,11 +149,13 @@ typedef struct options {
|
|||
bool debug_mode;
|
||||
// === General ===
|
||||
/// Use the legacy backends?
|
||||
bool legacy_backends;
|
||||
bool use_legacy_backends;
|
||||
/// Path to write PID to.
|
||||
char *write_pid_path;
|
||||
/// The backend in use.
|
||||
int backend;
|
||||
/// Name of the backend
|
||||
struct backend_info *backend;
|
||||
/// The backend in use (for legacy backends).
|
||||
int legacy_backend;
|
||||
/// Log level.
|
||||
int log_level;
|
||||
/// Whether to sync X drawing with X Sync fence to avoid certain delay
|
||||
|
@ -352,6 +345,8 @@ typedef struct options {
|
|||
|
||||
extern const char *const BACKEND_STRS[NUM_BKEND + 1];
|
||||
|
||||
bool load_plugin(const char *name, const char *include_dir);
|
||||
|
||||
bool must_use parse_long(const char *, long *);
|
||||
bool must_use parse_int(const char *, int *);
|
||||
struct conv **must_use parse_blur_kern_lst(const char *, int *count);
|
||||
|
@ -407,7 +402,6 @@ static inline attr_pure int parse_backend(const char *str) {
|
|||
"version will be removed soon.");
|
||||
return BKEND_XR_GLX_HYBRID;
|
||||
}
|
||||
log_error("Invalid backend argument: %s", str);
|
||||
return NUM_BKEND;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <libconfig.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "backend/backend.h"
|
||||
#include "c2.h"
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
|
@ -628,6 +629,37 @@ bool parse_config_libconfig(options_t *opt, const char *config_file) {
|
|||
// Get options from the configuration file. We don't do range checking
|
||||
// right now. It will be done later
|
||||
|
||||
// Load user specified plugins at the very beginning, because list of backends
|
||||
// depends on the plugins loaded.
|
||||
auto plugins = config_lookup(&cfg, "plugins");
|
||||
if (plugins != NULL) {
|
||||
sval = config_setting_get_string(plugins);
|
||||
if (sval) {
|
||||
if (!load_plugin(sval, NULL)) {
|
||||
log_fatal("Failed to load plugin \"%s\".", sval);
|
||||
goto out;
|
||||
}
|
||||
} else if (config_setting_is_array(plugins) || config_setting_is_list(plugins)) {
|
||||
for (int i = 0; i < config_setting_length(plugins); i++) {
|
||||
sval = config_setting_get_string_elem(plugins, i);
|
||||
if (!sval) {
|
||||
log_fatal("Invalid value for \"plugins\" at line "
|
||||
"%d.",
|
||||
config_setting_source_line(plugins));
|
||||
goto out;
|
||||
}
|
||||
if (!load_plugin(sval, NULL)) {
|
||||
log_fatal("Failed to load plugin \"%s\".", sval);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_fatal("Invalid value for \"plugins\" at line %d.",
|
||||
config_setting_source_line(plugins));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
// --dbus
|
||||
lcfg_lookup_bool(&cfg, "dbus", &opt->dbus);
|
||||
|
||||
|
@ -743,9 +775,10 @@ bool parse_config_libconfig(options_t *opt, const char *config_file) {
|
|||
lcfg_lookup_bool(&cfg, "vsync", &opt->vsync);
|
||||
// --backend
|
||||
if (config_lookup_string(&cfg, "backend", &sval)) {
|
||||
opt->backend = parse_backend(sval);
|
||||
if (opt->backend >= NUM_BKEND) {
|
||||
log_fatal("Cannot parse backend");
|
||||
opt->legacy_backend = parse_backend(sval);
|
||||
opt->backend = backend_find(sval);
|
||||
if (opt->legacy_backend >= NUM_BKEND && opt->backend == NULL) {
|
||||
log_fatal("Invalid backend: %s", sval);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
|
21
src/dbus.c
21
src/dbus.c
|
@ -20,15 +20,15 @@
|
|||
#include <unistd.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "backend/backend.h"
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "string_utils.h"
|
||||
#include "transition.h"
|
||||
#include "types.h"
|
||||
#include "uthash_extra.h"
|
||||
#include "utils.h"
|
||||
#include "win.h"
|
||||
#include "win_defs.h"
|
||||
|
@ -853,7 +853,6 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBus
|
|||
dbus_set_error_const(err, DBUS_ERROR_INVALID_ARGS, NULL);
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
assert((size_t)ps->o.backend < sizeof(BACKEND_STRS) / sizeof(BACKEND_STRS[0]));
|
||||
|
||||
#define append(tgt, type, ret) \
|
||||
if (!strcmp(#tgt, target)) { \
|
||||
|
@ -864,6 +863,18 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBus
|
|||
}
|
||||
#define append_session_option(tgt, type) append(tgt, type, ps->o.tgt)
|
||||
|
||||
if (!strcmp("backend", target)) {
|
||||
assert(!ps->o.use_legacy_backends ||
|
||||
(size_t)ps->o.legacy_backend < ARR_SIZE(BACKEND_STRS));
|
||||
const char *name = ps->o.use_legacy_backends
|
||||
? BACKEND_STRS[ps->o.legacy_backend]
|
||||
: backend_name(ps->o.backend);
|
||||
if (reply != NULL && !cdbus_append_string(reply, name)) {
|
||||
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||
}
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
append(version, string, PICOM_VERSION);
|
||||
append(pid, int32, getpid());
|
||||
append(display, string, DisplayString(ps->c.dpy));
|
||||
|
@ -875,7 +886,7 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBus
|
|||
append(unredir_if_possible_delay, int32, (int32_t)ps->o.unredir_if_possible_delay);
|
||||
append(refresh_rate, int32, 0);
|
||||
append(sw_opti, boolean, false);
|
||||
append(backend, string, BACKEND_STRS[ps->o.backend]);
|
||||
append(backend, string, BACKEND_STRS[ps->o.legacy_backend]);
|
||||
|
||||
append_session_option(unredir_if_possible, boolean);
|
||||
append_session_option(write_pid_path, string);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <xcb/composite.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include "backend/backend.h"
|
||||
#include "backend/driver.h"
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
|
@ -44,17 +45,17 @@ void print_diagnostics(session_t *ps, const char *config_file, bool compositor_r
|
|||
printf("\n### Drivers (inaccurate):\n\n");
|
||||
print_drivers(ps->drivers);
|
||||
|
||||
for (int i = 0; i < NUM_BKEND; i++) {
|
||||
if (backend_list[i] && backend_list[i]->diagnostics) {
|
||||
printf("\n### Backend: %s\n\n", BACKEND_STRS[i]);
|
||||
auto data = backend_list[i]->init(ps, session_get_target_window(ps));
|
||||
if (!data) {
|
||||
printf(" Cannot initialize this backend\n");
|
||||
} else {
|
||||
backend_list[i]->diagnostics(data);
|
||||
backend_list[i]->deinit(data);
|
||||
}
|
||||
for (auto i = backend_iter(); i; i = backend_iter_next(i)) {
|
||||
auto backend_data = backend_init(i, ps, session_get_target_window(ps));
|
||||
if (!backend_data) {
|
||||
printf(" Cannot initialize backend %s\n", backend_name(i));
|
||||
continue;
|
||||
}
|
||||
if (backend_data->ops.diagnostics) {
|
||||
printf("\n### Backend: %s\n\n", backend_name(i));
|
||||
backend_data->ops.diagnostics(backend_data);
|
||||
}
|
||||
backend_data->ops.deinit(backend_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include <xcb/xcb_event.h>
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "atom.h"
|
||||
#include "c2.h"
|
||||
#include "common.h"
|
||||
|
@ -20,7 +22,6 @@
|
|||
#include "log.h"
|
||||
#include "picom.h"
|
||||
#include "region.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "win.h"
|
||||
#include "win_defs.h"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "compiler.h"
|
||||
|
|
|
@ -11,8 +11,8 @@ srcs = [ files('picom.c', 'win.c', 'c2.c', 'x.c', 'config.c', 'vsync.c', 'utils.
|
|||
'diagnostic.c', 'string_utils.c', 'render.c', 'kernel.c', 'log.c',
|
||||
'options.c', 'event.c', 'cache.c', 'atom.c', 'file_watch.c', 'statistics.c',
|
||||
'vblank.c', 'transition.c', 'wm.c', 'renderer/layout.c', 'renderer/command_builder.c',
|
||||
'renderer/renderer.c', 'renderer/damage.c', 'config_libconfig.c', 'inspect.c', 'script.c') ]
|
||||
picom_inc = include_directories('.')
|
||||
'renderer/renderer.c', 'renderer/damage.c', 'config_libconfig.c', 'inspect.c', 'script.c', 'api.c') ]
|
||||
picom_inc = include_directories(['.', '../include'])
|
||||
|
||||
cflags = []
|
||||
|
||||
|
@ -86,7 +86,8 @@ subdir('backend')
|
|||
|
||||
picom = executable('picom', srcs, c_args: cflags,
|
||||
dependencies: [ base_deps, deps, test_h_dep ],
|
||||
install: true, include_directories: picom_inc)
|
||||
install: true, include_directories: picom_inc,
|
||||
export_dynamic: true, gnu_symbol_visibility: 'hidden')
|
||||
|
||||
if get_option('unittest')
|
||||
test('picom unittest', picom, args: [ '--unittest' ])
|
||||
|
|
|
@ -642,7 +642,7 @@ static inline GLuint glx_gen_texture(GLenum tex_tgt, int width, int height) {
|
|||
*/
|
||||
bool glx_bind_texture(session_t *ps attr_unused, glx_texture_t **pptex, int x, int y,
|
||||
int width, int height) {
|
||||
if (ps->o.backend != BKEND_GLX && ps->o.backend != BKEND_XR_GLX_HYBRID) {
|
||||
if (ps->o.legacy_backend != BKEND_GLX && ps->o.legacy_backend != BKEND_XR_GLX_HYBRID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -698,7 +698,7 @@ bool glx_bind_texture(session_t *ps attr_unused, glx_texture_t **pptex, int x, i
|
|||
*/
|
||||
bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap, int width,
|
||||
int height, bool repeat, const struct glx_fbconfig_info *fbcfg) {
|
||||
if (ps->o.backend != BKEND_GLX && ps->o.backend != BKEND_XR_GLX_HYBRID) {
|
||||
if (ps->o.legacy_backend != BKEND_GLX && ps->o.legacy_backend != BKEND_XR_GLX_HYBRID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
289
src/options.c
289
src/options.c
|
@ -298,6 +298,18 @@ store_benchmark_wid(const struct picom_option * /*opt*/, const struct picom_arg
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool store_backend(const struct picom_option * /*opt*/, const struct picom_arg * /*arg*/,
|
||||
const char *arg_str, void *output) {
|
||||
struct options *opt = (struct options *)output;
|
||||
opt->legacy_backend = parse_backend(arg_str);
|
||||
opt->backend = backend_find(arg_str);
|
||||
if (opt->legacy_backend == NUM_BKEND && opt->backend == NULL) {
|
||||
log_error("Invalid backend: %s", arg_str);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define WINDOW_SHADER_RULE \
|
||||
{ .parse_prefix = parse_window_shader_prefix_with_cwd, .free_value = free, }
|
||||
|
||||
|
@ -320,6 +332,7 @@ static const struct picom_option picom_options[] = {
|
|||
[314] = {"show-all-xerrors", IGNORE(no_argument)},
|
||||
['b'] = {"daemon" , IGNORE(no_argument) , "Daemonize process."},
|
||||
[256] = {"config" , IGNORE(required_argument), "Path to the configuration file."},
|
||||
[307] = {"plugins" , IGNORE(required_argument), "Plugins to load. Can be specified multiple times, each time with a single plugin."},
|
||||
|
||||
// Simple flags
|
||||
['c'] = {"shadow" , ENABLE(shadow_enable) , "Enabled client-side shadows on windows."},
|
||||
|
@ -380,7 +393,7 @@ static const struct picom_option picom_options[] = {
|
|||
"rendered screen. Reduces banding artifacts, but might cause performance "
|
||||
"degradation. Only works with OpenGL."},
|
||||
[341] = {"no-frame-pacing" , DISABLE(frame_pacing) , "Disable frame pacing. This might increase the latency."},
|
||||
[733] = {"legacy-backends" , ENABLE(legacy_backends) , "Use deprecated version of the backends."},
|
||||
[733] = {"legacy-backends" , ENABLE(use_legacy_backends) , "Use deprecated version of the backends."},
|
||||
[800] = {"monitor-repaint" , ENABLE(monitor_repaint) , "Highlight the updated area of the screen. For debugging."},
|
||||
[801] = {"diagnostics" , ENABLE(print_diagnostics) , "Print diagnostic information"},
|
||||
[802] = {"debug-mode" , ENABLE(debug_mode) , "Render into a separate window, and don't take over the screen. Useful when "
|
||||
|
@ -405,7 +418,7 @@ static const struct picom_option picom_options[] = {
|
|||
[259] = {"shadow-blue" , FLOAT(shadow_blue, 0, 1) , "Blue color value of shadow (0.0 - 1.0, defaults to 0)."},
|
||||
[261] = {"inactive-dim" , FLOAT(inactive_dim, 0, 1) , "Dim inactive windows. (0.0 - 1.0, defaults to 0)"},
|
||||
[283] = {"blur-background" , FIXED(blur_method, BLUR_METHOD_KERNEL) , "Blur background of semi-transparent / ARGB windows. May impact performance"},
|
||||
[290] = {"backend" , PARSE_WITH(parse_backend, NUM_BKEND, backend) , "Backend. Possible values are: " BACKENDS},
|
||||
[290] = {"backend" , DO(store_backend) , "Backend. Possible values are: " BACKENDS},
|
||||
[293] = {"benchmark" , INTEGER(benchmark, 0, INT_MAX) , "Benchmark mode. Repeatedly paint until reaching the specified cycles."},
|
||||
[297] = {"active-opacity" , FLOAT(active_opacity, 0, 1) , "Default opacity for active windows. (0.0 - 1.0)"},
|
||||
[302] = {"resize-damage" , INTEGER(resize_damage, INT_MIN, INT_MAX)}, // only used by legacy backends
|
||||
|
@ -483,7 +496,7 @@ static const struct picom_option picom_options[] = {
|
|||
['z'] = {"clear-shadow" , SAY_DEPRECATED(false, CLEAR_SHADOW_DEPRECATION , IGNORE(no_argument))},
|
||||
[272] = {"xinerama-shadow-crop", SAY_DEPRECATED(false, "Use --crop-shadow-to-monitor instead.", ENABLE(crop_shadow_to_monitor))},
|
||||
[287] = {"logpath" , SAY_DEPRECATED(false, "Use --log-file instead." , STRING(logpath))},
|
||||
[289] = {"opengl" , SAY_DEPRECATED(false, "Use --backend=glx instead." , FIXED(backend, BKEND_GLX))},
|
||||
[289] = {"opengl" , SAY_DEPRECATED(false, "Use --backend=glx instead." , FIXED(legacy_backend, BKEND_GLX))},
|
||||
[305] = {"shadow-exclude-reg" , SAY_DEPRECATED(true, "Use --clip-shadow-above instead." , REJECT(required_argument))},
|
||||
|
||||
#undef CLEAR_SHADOW_DEPRECATION
|
||||
|
@ -679,6 +692,7 @@ bool get_early_config(int argc, char *const *argv, char **config_file, bool *all
|
|||
bool *fork, int *exit_code) {
|
||||
setup_longopts();
|
||||
|
||||
scoped_charp current_working_dir = getcwd(NULL, 0);
|
||||
int o = 0, longopt_idx = -1;
|
||||
|
||||
// Pre-parse the command line arguments to check for --config and invalid
|
||||
|
@ -694,7 +708,6 @@ bool get_early_config(int argc, char *const *argv, char **config_file, bool *all
|
|||
} else if (o == 'h') {
|
||||
usage(argv[0], 0);
|
||||
return true;
|
||||
|
||||
} else if (o == 'b') {
|
||||
*fork = true;
|
||||
} else if (o == 314) {
|
||||
|
@ -702,10 +715,17 @@ bool get_early_config(int argc, char *const *argv, char **config_file, bool *all
|
|||
} else if (o == 318) {
|
||||
printf("%s\n", PICOM_VERSION);
|
||||
return true;
|
||||
} else if (o == 307) {
|
||||
// --plugin
|
||||
if (!load_plugin(optarg, current_working_dir)) {
|
||||
log_error("Failed to load plugin %s", optarg);
|
||||
goto err;
|
||||
}
|
||||
} else if (o == '?' || o == ':') {
|
||||
usage(argv[0], 1);
|
||||
goto err;
|
||||
}
|
||||
// TODO(yshui) maybe log-level should be handled here.
|
||||
}
|
||||
|
||||
// Check for abundant positional arguments
|
||||
|
@ -721,6 +741,143 @@ err:
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool sanitize_options(struct options *opt) {
|
||||
if (opt->use_legacy_backends) {
|
||||
if (opt->legacy_backend == BKEND_EGL) {
|
||||
log_error("The egl backend is not supported with "
|
||||
"--legacy-backends");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opt->monitor_repaint && opt->legacy_backend != BKEND_XRENDER) {
|
||||
log_warn("For legacy backends, --monitor-repaint is only "
|
||||
"implemented for "
|
||||
"xrender.");
|
||||
}
|
||||
|
||||
if (opt->debug_mode) {
|
||||
log_error("Debug mode does not work with the legacy backends.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opt->transparent_clipping) {
|
||||
log_error("Transparent clipping does not work with the legacy "
|
||||
"backends");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opt->max_brightness < 1.0) {
|
||||
log_warn("--max-brightness is not supported by the legacy "
|
||||
"backends. Falling back to 1.0.");
|
||||
opt->max_brightness = 1.0;
|
||||
}
|
||||
|
||||
if (opt->blur_method == BLUR_METHOD_DUAL_KAWASE) {
|
||||
log_warn("Dual-kawase blur is not implemented by the legacy "
|
||||
"backends.");
|
||||
opt->blur_method = BLUR_METHOD_NONE;
|
||||
}
|
||||
|
||||
if (opt->number_of_scripts > 0) {
|
||||
log_warn("Custom animations are not supported by the legacy "
|
||||
"backends. Disabling animations.");
|
||||
for (size_t i = 0; i < ARR_SIZE(opt->animations); i++) {
|
||||
opt->animations[i].script = NULL;
|
||||
}
|
||||
for (int i = 0; i < opt->number_of_scripts; i++) {
|
||||
script_free(opt->all_scripts[i]);
|
||||
}
|
||||
free(opt->all_scripts);
|
||||
opt->all_scripts = NULL;
|
||||
opt->number_of_scripts = 0;
|
||||
}
|
||||
|
||||
if (opt->window_shader_fg || opt->window_shader_fg_rules) {
|
||||
log_warn("The new shader interface is not supported by the "
|
||||
"legacy glx backend. You may want to use "
|
||||
"--glx-fshader-win instead.");
|
||||
opt->window_shader_fg = NULL;
|
||||
c2_list_free(&opt->window_shader_fg_rules, free);
|
||||
}
|
||||
|
||||
if (opt->legacy_backend == BKEND_XRENDER) {
|
||||
bool has_neg = false;
|
||||
for (int i = 0; i < opt->blur_kernel_count; i++) {
|
||||
auto kernel = opt->blur_kerns[i];
|
||||
for (int j = 0; j < kernel->h * kernel->w; j++) {
|
||||
if (kernel->data[j] < 0) {
|
||||
has_neg = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has_neg) {
|
||||
log_warn("A convolution kernel with negative "
|
||||
"values may not work properly under X "
|
||||
"Render backend.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (opt->backend == NULL) {
|
||||
auto valid_backend_name =
|
||||
backend_find(BACKEND_STRS[opt->legacy_backend]) != NULL;
|
||||
if (!valid_backend_name) {
|
||||
log_error("Backend \"%s\" is only available as part of "
|
||||
"the legacy backends.",
|
||||
BACKEND_STRS[opt->legacy_backend]);
|
||||
} else {
|
||||
// If the backend name is a valid new backend, then
|
||||
// it must not have been specified by the user, because
|
||||
// otherwise opt->backend wouldn't be NULL.
|
||||
log_error("Backend not specified. You must choose one "
|
||||
"explicitly. Valid ones are: ");
|
||||
for (auto i = backend_iter(); i; i = backend_iter_next(i)) {
|
||||
log_error("\t%s", backend_name(i));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opt->glx_fshader_win_str) {
|
||||
log_warn("--glx-fshader-win has been replaced by "
|
||||
"\"--window-shader-fg\" for the new backends.");
|
||||
}
|
||||
|
||||
if (opt->max_brightness < 1.0 && opt->use_damage) {
|
||||
log_warn("--max-brightness requires --no-use-damage. "
|
||||
"Falling back to 1.0.");
|
||||
opt->max_brightness = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (opt->write_pid_path && *opt->write_pid_path != '/') {
|
||||
log_warn("--write-pid-path is not an absolute path");
|
||||
}
|
||||
|
||||
// Sanitize parameters for dual-filter kawase blur
|
||||
if (opt->blur_method == BLUR_METHOD_DUAL_KAWASE) {
|
||||
if (opt->blur_strength <= 0 && opt->blur_radius > 500) {
|
||||
log_warn("Blur radius >500 not supported by dual_kawase "
|
||||
"method, "
|
||||
"capping to 500.");
|
||||
opt->blur_radius = 500;
|
||||
}
|
||||
if (opt->blur_strength > 20) {
|
||||
log_warn("Blur strength >20 not supported by dual_kawase "
|
||||
"method, "
|
||||
"capping to 20.");
|
||||
opt->blur_strength = 20;
|
||||
}
|
||||
}
|
||||
|
||||
if (opt->resize_damage < 0) {
|
||||
log_warn("Negative --resize-damage will not work correctly.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process arguments and configuration files.
|
||||
*/
|
||||
|
@ -748,83 +905,22 @@ bool get_cfg(options_t *opt, int argc, char *const *argv) {
|
|||
}
|
||||
|
||||
log_set_level_tls(opt->log_level);
|
||||
if (opt->monitor_repaint && opt->backend != BKEND_XRENDER && opt->legacy_backends) {
|
||||
log_warn("--monitor-repaint has no effect when backend is not xrender");
|
||||
}
|
||||
|
||||
if (opt->window_shader_fg) {
|
||||
scoped_charp cwd = getcwd(NULL, 0);
|
||||
scoped_charp tmp = opt->window_shader_fg;
|
||||
opt->window_shader_fg = locate_auxiliary_file("shaders", tmp, cwd);
|
||||
if (!opt->window_shader_fg) {
|
||||
log_error("Couldn't find the specified window shader file \"%s\"", tmp);
|
||||
log_error("Couldn't find the specified window shader "
|
||||
"file \"%s\"",
|
||||
tmp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (opt->write_pid_path && *opt->write_pid_path != '/') {
|
||||
log_warn("--write-pid-path is not an absolute path");
|
||||
}
|
||||
|
||||
if (opt->backend == BKEND_EGL) {
|
||||
if (opt->legacy_backends) {
|
||||
log_error("The egl backend is not supported with "
|
||||
"--legacy-backends");
|
||||
return false;
|
||||
}
|
||||
log_warn("The egl backend is still experimental, use with care.");
|
||||
}
|
||||
|
||||
if (!opt->legacy_backends && !backend_list[opt->backend]) {
|
||||
log_error("Backend \"%s\" is only available as part of the legacy "
|
||||
"backends.",
|
||||
BACKEND_STRS[opt->backend]);
|
||||
if (!sanitize_options(opt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opt->debug_mode && opt->legacy_backends) {
|
||||
log_error("Debug mode does not work with the legacy backends.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opt->transparent_clipping && opt->legacy_backends) {
|
||||
log_error("Transparent clipping does not work with the legacy "
|
||||
"backends");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opt->glx_fshader_win_str && !opt->legacy_backends) {
|
||||
log_warn("--glx-fshader-win has been replaced by "
|
||||
"\"--window-shader-fg\" for the new backends.");
|
||||
}
|
||||
|
||||
if (opt->window_shader_fg || opt->window_shader_fg_rules) {
|
||||
if (opt->backend == BKEND_XRENDER || opt->legacy_backends) {
|
||||
log_warn(opt->backend == BKEND_XRENDER
|
||||
? "Shader interface is not supported by the xrender "
|
||||
"backend."
|
||||
: "The new shader interface is not supported by the "
|
||||
"legacy glx backend. You may want to use "
|
||||
"--glx-fshader-win instead.");
|
||||
opt->window_shader_fg = NULL;
|
||||
c2_list_free(&opt->window_shader_fg_rules, free);
|
||||
}
|
||||
}
|
||||
|
||||
// Range checking and option assignments
|
||||
if (opt->max_brightness < 1.0) {
|
||||
if (opt->backend == BKEND_XRENDER || opt->legacy_backends) {
|
||||
log_warn("--max-brightness is not supported by the %s backend. "
|
||||
"Falling back to 1.0.",
|
||||
opt->backend == BKEND_XRENDER ? "xrender" : "legacy glx");
|
||||
opt->max_brightness = 1.0;
|
||||
} else if (opt->use_damage) {
|
||||
log_warn("--max-brightness requires --no-use-damage. Falling "
|
||||
"back to 1.0.");
|
||||
opt->max_brightness = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
// --blur-background-frame implies --blur-background
|
||||
if (opt->blur_background_frame && opt->blur_method == BLUR_METHOD_NONE) {
|
||||
opt->blur_method = BLUR_METHOD_KERNEL;
|
||||
|
@ -846,57 +942,6 @@ bool get_cfg(options_t *opt, int argc, char *const *argv) {
|
|||
CHECK(opt->blur_kernel_count);
|
||||
}
|
||||
|
||||
// Sanitize parameters for dual-filter kawase blur
|
||||
if (opt->blur_method == BLUR_METHOD_DUAL_KAWASE) {
|
||||
if (opt->blur_strength <= 0 && opt->blur_radius > 500) {
|
||||
log_warn("Blur radius >500 not supported by dual_kawase method, "
|
||||
"capping to 500.");
|
||||
opt->blur_radius = 500;
|
||||
}
|
||||
if (opt->blur_strength > 20) {
|
||||
log_warn("Blur strength >20 not supported by dual_kawase method, "
|
||||
"capping to 20.");
|
||||
opt->blur_strength = 20;
|
||||
}
|
||||
if (opt->legacy_backends) {
|
||||
log_warn("Dual-kawase blur is not implemented by the legacy "
|
||||
"backends.");
|
||||
}
|
||||
}
|
||||
|
||||
if (opt->resize_damage < 0) {
|
||||
log_warn("Negative --resize-damage will not work correctly.");
|
||||
}
|
||||
|
||||
if (opt->backend == BKEND_XRENDER) {
|
||||
for (int i = 0; i < opt->blur_kernel_count; i++) {
|
||||
auto kernel = opt->blur_kerns[i];
|
||||
for (int j = 0; j < kernel->h * kernel->w; j++) {
|
||||
if (kernel->data[j] < 0) {
|
||||
log_warn("A convolution kernel with negative "
|
||||
"values may not work properly under X "
|
||||
"Render backend.");
|
||||
goto check_end;
|
||||
}
|
||||
}
|
||||
}
|
||||
check_end:;
|
||||
}
|
||||
|
||||
if (opt->legacy_backends && opt->number_of_scripts > 0) {
|
||||
log_warn("Custom animations are not supported by the legacy "
|
||||
"backends. Disabling animations.");
|
||||
for (size_t i = 0; i < ARR_SIZE(opt->animations); i++) {
|
||||
opt->animations[i].script = NULL;
|
||||
}
|
||||
for (int i = 0; i < opt->number_of_scripts; i++) {
|
||||
script_free(opt->all_scripts[i]);
|
||||
}
|
||||
free(opt->all_scripts);
|
||||
opt->all_scripts = NULL;
|
||||
opt->number_of_scripts = 0;
|
||||
}
|
||||
|
||||
if (opt->fading_enable) {
|
||||
generate_fading_config(opt);
|
||||
}
|
||||
|
@ -918,8 +963,8 @@ void options_postprocess_c2_lists(struct c2_state *state, struct x_connection *c
|
|||
c2_list_postprocess(state, c->c, option->corner_radius_rules) &&
|
||||
c2_list_postprocess(state, c->c, option->focus_blacklist) &&
|
||||
c2_list_postprocess(state, c->c, option->transparent_clipping_blacklist))) {
|
||||
log_error("Post-processing of conditionals failed, some of your rules "
|
||||
"might not work");
|
||||
log_error("Post-processing of conditionals failed, some of your "
|
||||
"rules might not work");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
#include <stdbool.h>
|
||||
#include <xcb/render.h> // for xcb_render_fixed_t
|
||||
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "win.h" // for wintype_t
|
||||
|
||||
typedef struct session session_t;
|
||||
|
||||
|
|
134
src/picom.c
134
src/picom.c
|
@ -15,7 +15,7 @@
|
|||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/extensions/sync.h>
|
||||
#include <errno.h>
|
||||
#include <ev.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <libgen.h>
|
||||
|
@ -38,17 +38,16 @@
|
|||
#include <xcb/xcb_aux.h>
|
||||
#include <xcb/xfixes.h>
|
||||
|
||||
#include <ev.h>
|
||||
#include <picom/types.h>
|
||||
#include <test.h>
|
||||
|
||||
#include "api_internal.h"
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "err.h"
|
||||
#include "inspect.h"
|
||||
#include "kernel.h"
|
||||
#include "picom.h"
|
||||
#include "transition.h"
|
||||
#include "win_defs.h"
|
||||
#include "wm.h"
|
||||
#ifdef CONFIG_OPENGL
|
||||
|
@ -70,7 +69,6 @@
|
|||
#include "renderer/layout.h"
|
||||
#include "renderer/renderer.h"
|
||||
#include "statistics.h"
|
||||
#include "types.h"
|
||||
#include "uthash_extra.h"
|
||||
#include "utils.h"
|
||||
#include "vblank.h"
|
||||
|
@ -154,7 +152,7 @@ enum vblank_callback_action check_render_finish(struct vblank_event *e attr_unus
|
|||
|
||||
struct timespec render_time;
|
||||
bool completed =
|
||||
ps->backend_data->ops->last_render_time(ps->backend_data, &render_time);
|
||||
ps->backend_data->ops.last_render_time(ps->backend_data, &render_time);
|
||||
if (!completed) {
|
||||
// Render hasn't completed yet, we can't start another render.
|
||||
// Check again at the next vblank.
|
||||
|
@ -440,7 +438,7 @@ void add_damage(session_t *ps, const region_t *damage) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!damage) {
|
||||
if (!damage || ps->damage_ring.count <= 0) {
|
||||
return;
|
||||
}
|
||||
log_trace("Adding damage: ");
|
||||
|
@ -577,14 +575,14 @@ static void destroy_backend(session_t *ps) {
|
|||
|
||||
HASH_ITER2(ps->shaders, shader) {
|
||||
if (shader->backend_shader != NULL) {
|
||||
ps->backend_data->ops->destroy_shader(ps->backend_data,
|
||||
shader->backend_shader);
|
||||
ps->backend_data->ops.destroy_shader(ps->backend_data,
|
||||
shader->backend_shader);
|
||||
shader->backend_shader = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ps->backend_data && ps->root_image) {
|
||||
ps->backend_data->ops->release_image(ps->backend_data, ps->root_image);
|
||||
ps->backend_data->ops.release_image(ps->backend_data, ps->root_image);
|
||||
ps->root_image = NULL;
|
||||
}
|
||||
|
||||
|
@ -595,11 +593,11 @@ static void destroy_backend(session_t *ps) {
|
|||
}
|
||||
// deinit backend
|
||||
if (ps->backend_blur_context) {
|
||||
ps->backend_data->ops->destroy_blur_context(
|
||||
ps->backend_data->ops.destroy_blur_context(
|
||||
ps->backend_data, ps->backend_blur_context);
|
||||
ps->backend_blur_context = NULL;
|
||||
}
|
||||
ps->backend_data->ops->deinit(ps->backend_data);
|
||||
ps->backend_data->ops.deinit(ps->backend_data);
|
||||
ps->backend_data = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -637,7 +635,7 @@ static bool initialize_blur(session_t *ps) {
|
|||
enum backend_image_format format = ps->o.dithered_present
|
||||
? BACKEND_IMAGE_FORMAT_PIXMAP_HIGH
|
||||
: BACKEND_IMAGE_FORMAT_PIXMAP;
|
||||
ps->backend_blur_context = ps->backend_data->ops->create_blur_context(
|
||||
ps->backend_blur_context = ps->backend_data->ops.create_blur_context(
|
||||
ps->backend_data, ps->o.blur_method, format, args);
|
||||
return ps->backend_blur_context != NULL;
|
||||
}
|
||||
|
@ -658,18 +656,17 @@ static int mark_pixmap_stale(struct win *w, void *data) {
|
|||
|
||||
/// Init the backend and bind all the window pixmap to backend images
|
||||
static bool initialize_backend(session_t *ps) {
|
||||
if (!ps->o.legacy_backends) {
|
||||
if (!ps->o.use_legacy_backends) {
|
||||
assert(!ps->backend_data);
|
||||
// Reinitialize win_data
|
||||
assert(backend_list[ps->o.backend]);
|
||||
ps->backend_data =
|
||||
backend_list[ps->o.backend]->init(ps, session_get_target_window(ps));
|
||||
backend_init(ps->o.backend, ps, session_get_target_window(ps));
|
||||
api_backend_plugins_invoke(backend_name(ps->o.backend), ps->backend_data);
|
||||
if (!ps->backend_data) {
|
||||
log_fatal("Failed to initialize backend, aborting...");
|
||||
quit(ps);
|
||||
return false;
|
||||
}
|
||||
ps->backend_data->ops = backend_list[ps->o.backend];
|
||||
|
||||
if (!initialize_blur(ps)) {
|
||||
log_fatal("Failed to prepare for background blur, aborting...");
|
||||
|
@ -677,24 +674,30 @@ static bool initialize_backend(session_t *ps) {
|
|||
}
|
||||
|
||||
// Create shaders
|
||||
HASH_ITER2(ps->shaders, shader) {
|
||||
assert(shader->backend_shader == NULL);
|
||||
shader->backend_shader = ps->backend_data->ops->create_shader(
|
||||
ps->backend_data, shader->source);
|
||||
if (shader->backend_shader == NULL) {
|
||||
log_warn("Failed to create shader for shader file %s, "
|
||||
"this shader will not be used",
|
||||
shader->key);
|
||||
} else {
|
||||
if (ps->backend_data->ops->get_shader_attributes) {
|
||||
shader->attributes =
|
||||
ps->backend_data->ops->get_shader_attributes(
|
||||
ps->backend_data, shader->backend_shader);
|
||||
if (!ps->backend_data->ops.create_shader && ps->shaders) {
|
||||
log_warn("Shaders are not supported by selected backend %s, "
|
||||
"they will be ignored",
|
||||
backend_name(ps->o.backend));
|
||||
} else {
|
||||
HASH_ITER2(ps->shaders, shader) {
|
||||
assert(shader->backend_shader == NULL);
|
||||
shader->backend_shader = ps->backend_data->ops.create_shader(
|
||||
ps->backend_data, shader->source);
|
||||
if (shader->backend_shader == NULL) {
|
||||
log_warn("Failed to create shader for shader "
|
||||
"file %s, this shader will not be used",
|
||||
shader->key);
|
||||
} else {
|
||||
shader->attributes = 0;
|
||||
if (ps->backend_data->ops.get_shader_attributes) {
|
||||
shader->attributes =
|
||||
ps->backend_data->ops.get_shader_attributes(
|
||||
ps->backend_data,
|
||||
shader->backend_shader);
|
||||
}
|
||||
log_debug("Shader %s has attributes %" PRIu64,
|
||||
shader->key, shader->attributes);
|
||||
}
|
||||
log_debug("Shader %s has attributes %" PRIu64,
|
||||
shader->key, shader->attributes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -716,7 +719,7 @@ static bool initialize_backend(session_t *ps) {
|
|||
// The old backends binds pixmap lazily, nothing to do here
|
||||
return true;
|
||||
err:
|
||||
ps->backend_data->ops->deinit(ps->backend_data);
|
||||
ps->backend_data->ops.deinit(ps->backend_data);
|
||||
ps->backend_data = NULL;
|
||||
quit(ps);
|
||||
return false;
|
||||
|
@ -736,9 +739,9 @@ static void configure_root(session_t *ps) {
|
|||
bool has_root_change = false;
|
||||
if (ps->redirected) {
|
||||
// On root window changes
|
||||
if (!ps->o.legacy_backends) {
|
||||
if (!ps->o.use_legacy_backends) {
|
||||
assert(ps->backend_data);
|
||||
has_root_change = ps->backend_data->ops->root_change != NULL;
|
||||
has_root_change = ps->backend_data->ops.root_change != NULL;
|
||||
} else {
|
||||
// Old backend can handle root change
|
||||
has_root_change = true;
|
||||
|
@ -779,13 +782,13 @@ static void configure_root(session_t *ps) {
|
|||
ps->damage_ring.cursor = ps->damage_ring.count - 1;
|
||||
#ifdef CONFIG_OPENGL
|
||||
// GLX root change callback
|
||||
if (BKEND_GLX == ps->o.backend && ps->o.legacy_backends) {
|
||||
if (BKEND_GLX == ps->o.legacy_backend && ps->o.use_legacy_backends) {
|
||||
glx_on_root_change(ps);
|
||||
}
|
||||
#endif
|
||||
if (has_root_change) {
|
||||
if (ps->backend_data != NULL) {
|
||||
ps->backend_data->ops->root_change(ps->backend_data, ps);
|
||||
ps->backend_data->ops.root_change(ps->backend_data, ps);
|
||||
}
|
||||
// Old backend's root_change is not a specific function
|
||||
} else {
|
||||
|
@ -1079,7 +1082,7 @@ void root_damaged(session_t *ps) {
|
|||
|
||||
if (ps->backend_data) {
|
||||
if (ps->root_image) {
|
||||
ps->backend_data->ops->release_image(ps->backend_data, ps->root_image);
|
||||
ps->backend_data->ops.release_image(ps->backend_data, ps->root_image);
|
||||
ps->root_image = NULL;
|
||||
}
|
||||
auto pixmap = x_get_root_back_pixmap(&ps->c, ps->atoms);
|
||||
|
@ -1113,7 +1116,7 @@ void root_damaged(session_t *ps) {
|
|||
: x_get_visual_for_depth(ps->c.screen_info, r->depth);
|
||||
free(r);
|
||||
|
||||
ps->root_image = ps->backend_data->ops->bind_pixmap(
|
||||
ps->root_image = ps->backend_data->ops.bind_pixmap(
|
||||
ps->backend_data, pixmap, x_get_visual_info(&ps->c, visual));
|
||||
ps->root_image_generation += 1;
|
||||
if (!ps->root_image) {
|
||||
|
@ -1375,10 +1378,10 @@ uint8_t session_redirection_mode(session_t *ps) {
|
|||
if (ps->o.debug_mode) {
|
||||
// If the backend is not rendering to the screen, we don't need to
|
||||
// take over the screen.
|
||||
assert(!ps->o.legacy_backends);
|
||||
assert(!ps->o.use_legacy_backends);
|
||||
return XCB_COMPOSITE_REDIRECT_AUTOMATIC;
|
||||
}
|
||||
if (!ps->o.legacy_backends && !backend_list[ps->o.backend]->present) {
|
||||
if (!ps->o.use_legacy_backends && !backend_can_present(ps->o.backend)) {
|
||||
// if the backend doesn't render anything, we don't need to take over the
|
||||
// screen.
|
||||
return XCB_COMPOSITE_REDIRECT_AUTOMATIC;
|
||||
|
@ -1415,11 +1418,11 @@ static bool redirect_start(session_t *ps) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!ps->o.legacy_backends) {
|
||||
if (!ps->o.use_legacy_backends) {
|
||||
assert(ps->backend_data);
|
||||
ps->damage_ring.count = ps->backend_data->ops->max_buffer_age;
|
||||
ps->layout_manager =
|
||||
layout_manager_new((unsigned)ps->backend_data->ops->max_buffer_age);
|
||||
ps->damage_ring.count =
|
||||
ps->backend_data->ops.max_buffer_age(ps->backend_data);
|
||||
ps->layout_manager = layout_manager_new((unsigned)ps->damage_ring.count);
|
||||
} else {
|
||||
ps->damage_ring.count = maximum_buffer_age(ps);
|
||||
}
|
||||
|
@ -1431,7 +1434,8 @@ static bool redirect_start(session_t *ps) {
|
|||
}
|
||||
|
||||
ps->frame_pacing = ps->o.frame_pacing && ps->o.vsync;
|
||||
if ((ps->o.legacy_backends || ps->o.benchmark || !ps->backend_data->ops->last_render_time) &&
|
||||
if ((ps->o.use_legacy_backends || ps->o.benchmark ||
|
||||
!ps->backend_data->ops.last_render_time) &&
|
||||
ps->frame_pacing) {
|
||||
// Disable frame pacing if we are using a legacy backend or if we are in
|
||||
// benchmark mode, or if the backend doesn't report render time
|
||||
|
@ -1777,7 +1781,7 @@ static void draw_callback_impl(EV_P_ session_t *ps, int revents attr_unused) {
|
|||
static int paint = 0;
|
||||
|
||||
log_verbose("Render start, frame %d", paint);
|
||||
if (!ps->o.legacy_backends) {
|
||||
if (!ps->o.use_legacy_backends) {
|
||||
uint64_t after_damage_us = 0;
|
||||
now = get_time_timespec();
|
||||
auto render_start_us =
|
||||
|
@ -2211,7 +2215,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
|||
}
|
||||
}
|
||||
|
||||
if (ps->o.legacy_backends) {
|
||||
if (ps->o.use_legacy_backends) {
|
||||
ps->shadow_context =
|
||||
(void *)gaussian_kernel_autodetect_deviation(ps->o.shadow_radius);
|
||||
sum_kernel_preprocess((conv *)ps->shadow_context);
|
||||
|
@ -2332,9 +2336,9 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
|||
|
||||
// The old backends doesn't have a automatic redirection mode
|
||||
log_info("The compositor is started in automatic redirection mode.");
|
||||
assert(!ps->o.legacy_backends);
|
||||
assert(!ps->o.use_legacy_backends);
|
||||
|
||||
if (backend_list[ps->o.backend]->present) {
|
||||
if (backend_can_present(ps->o.backend)) {
|
||||
// If the backend has `present`, we couldn't be in automatic
|
||||
// redirection mode unless we are in debug mode.
|
||||
assert(ps->o.debug_mode);
|
||||
|
@ -2348,7 +2352,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
|||
apply_driver_workarounds(ps, ps->drivers);
|
||||
|
||||
// Initialize filters, must be preceded by OpenGL context creation
|
||||
if (ps->o.legacy_backends && !init_render(ps)) {
|
||||
if (ps->o.use_legacy_backends && !init_render(ps)) {
|
||||
log_fatal("Failed to initialize the backend");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -2371,7 +2375,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
|||
}
|
||||
}
|
||||
|
||||
if (bkend_use_glx(ps) && ps->o.legacy_backends) {
|
||||
if (bkend_use_glx(ps) && ps->o.use_legacy_backends) {
|
||||
auto gl_logger = gl_string_marker_logger_new();
|
||||
if (gl_logger) {
|
||||
log_info("Enabling gl string marker");
|
||||
|
@ -2618,7 +2622,7 @@ static void session_destroy(session_t *ps) {
|
|||
ps->damage_ring.x_region = XCB_NONE;
|
||||
}
|
||||
|
||||
if (!ps->o.legacy_backends) {
|
||||
if (!ps->o.use_legacy_backends) {
|
||||
// backend is deinitialized in unredirect()
|
||||
assert(ps->backend_data == NULL);
|
||||
} else {
|
||||
|
@ -2635,7 +2639,7 @@ static void session_destroy(session_t *ps) {
|
|||
// Flush all events
|
||||
xcb_aux_sync(ps->c.c);
|
||||
ev_io_stop(ps->loop, &ps->xiow);
|
||||
if (ps->o.legacy_backends) {
|
||||
if (ps->o.use_legacy_backends) {
|
||||
free_conv((conv *)ps->shadow_context);
|
||||
}
|
||||
destroy_atoms(ps->atoms);
|
||||
|
@ -2684,6 +2688,18 @@ static void session_run(session_t *ps) {
|
|||
#define PICOM_MAIN(...) main(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/// Early initialization of logging system. To catch early logs, especially
|
||||
/// from backend entrypoint functions.
|
||||
static void __attribute__((constructor(201))) init_early_logging(void) {
|
||||
log_init_tls();
|
||||
log_set_level_tls(LOG_LEVEL_WARN);
|
||||
|
||||
auto stderr_logger = stderr_logger_new();
|
||||
if (stderr_logger != NULL) {
|
||||
log_add_target_tls(stderr_logger);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The function that everybody knows.
|
||||
*/
|
||||
|
@ -2692,16 +2708,6 @@ int PICOM_MAIN(int argc, char **argv) {
|
|||
// correctly
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
// Initialize logging system for early logging
|
||||
log_init_tls();
|
||||
|
||||
{
|
||||
auto stderr_logger = stderr_logger_new();
|
||||
if (stderr_logger) {
|
||||
log_add_target_tls(stderr_logger);
|
||||
}
|
||||
}
|
||||
|
||||
parse_debug_options(&global_debug_options);
|
||||
|
||||
int exit_code;
|
||||
|
|
|
@ -6,22 +6,20 @@
|
|||
|
||||
// === Includes ===
|
||||
|
||||
#include <X11/Xutil.h>
|
||||
#include <locale.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
#include <X11/Xutil.h>
|
||||
#include "backend/backend.h"
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "c2.h"
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "log.h" // XXX clean up
|
||||
#include "region.h"
|
||||
#include "render.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "win.h"
|
||||
#include "x.h"
|
||||
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
|
||||
#pragma once
|
||||
#include <pixman.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
|
||||
typedef struct pixman_region32 pixman_region32_t;
|
||||
|
|
41
src/render.c
41
src/render.c
|
@ -10,9 +10,10 @@
|
|||
#include <xcb/xcb_image.h>
|
||||
#include <xcb/xcb_renderutil.h>
|
||||
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "options.h"
|
||||
#include "transition.h"
|
||||
|
||||
#ifdef CONFIG_OPENGL
|
||||
#include "backend/gl/glx.h"
|
||||
|
@ -29,13 +30,11 @@
|
|||
#include "kernel.h"
|
||||
#include "log.h"
|
||||
#include "region.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "vsync.h"
|
||||
#include "win.h"
|
||||
#include "x.h"
|
||||
|
||||
#include "backend/backend.h"
|
||||
#include "backend/backend_common.h"
|
||||
#include "render.h"
|
||||
|
||||
|
@ -113,7 +112,8 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h
|
|||
* Check if current backend uses XRender for rendering.
|
||||
*/
|
||||
static inline bool bkend_use_xrender(session_t *ps) {
|
||||
return BKEND_XRENDER == ps->o.backend || BKEND_XR_GLX_HYBRID == ps->o.backend;
|
||||
return BKEND_XRENDER == ps->o.legacy_backend ||
|
||||
BKEND_XR_GLX_HYBRID == ps->o.legacy_backend;
|
||||
}
|
||||
|
||||
int maximum_buffer_age(session_t *ps) {
|
||||
|
@ -154,7 +154,7 @@ static inline void xrfilter_reset(session_t *ps, xcb_render_picture_t p) {
|
|||
|
||||
/// Set the input/output clip region of the target buffer (not the actual target!)
|
||||
static inline void attr_nonnull(1, 2) set_tgt_clip(session_t *ps, region_t *reg) {
|
||||
switch (ps->o.backend) {
|
||||
switch (ps->o.legacy_backend) {
|
||||
case BKEND_XRENDER:
|
||||
case BKEND_XR_GLX_HYBRID:
|
||||
x_set_picture_clip_region(&ps->c, ps->tgt_buffer.pict, 0, 0, reg);
|
||||
|
@ -243,7 +243,7 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f
|
|||
int fullhei, double opacity, bool argb, bool neg, int cr,
|
||||
xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint,
|
||||
const glx_prog_main_t *pprogram, clip_t *clip) {
|
||||
switch (ps->o.backend) {
|
||||
switch (ps->o.legacy_backend) {
|
||||
case BKEND_XRENDER:
|
||||
case BKEND_XR_GLX_HYBRID: {
|
||||
auto alpha_step = (int)(opacity * MAX_ALPHA);
|
||||
|
@ -381,7 +381,7 @@ static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) {
|
|||
}
|
||||
|
||||
#ifdef CONFIG_OPENGL
|
||||
if (BKEND_GLX == ps->o.backend && !glx_tex_bound(ppaint->ptex, XCB_NONE)) {
|
||||
if (BKEND_GLX == ps->o.legacy_backend && !glx_tex_bound(ppaint->ptex, XCB_NONE)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
@ -562,7 +562,7 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
|
|||
dim_opacity *= window_opacity;
|
||||
}
|
||||
|
||||
switch (ps->o.backend) {
|
||||
switch (ps->o.legacy_backend) {
|
||||
case BKEND_XRENDER:
|
||||
case BKEND_XR_GLX_HYBRID: {
|
||||
auto cval = (uint16_t)(0xffff * dim_opacity);
|
||||
|
@ -656,7 +656,7 @@ static bool get_root_tile(session_t *ps) {
|
|||
ps->root_tile_fill = fill;
|
||||
ps->root_tile_paint.pixmap = pixmap;
|
||||
#ifdef CONFIG_OPENGL
|
||||
if (BKEND_GLX == ps->o.backend) {
|
||||
if (BKEND_GLX == ps->o.legacy_backend) {
|
||||
return paint_bind_tex(ps, &ps->root_tile_paint, 0, 0, true, 0, visual, false);
|
||||
}
|
||||
#endif
|
||||
|
@ -775,7 +775,8 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) {
|
|||
bool should_clip =
|
||||
(w->corner_radius > 0) && (!ps->o.wintype_option[w->window_type].full_shadow);
|
||||
if (should_clip) {
|
||||
if (ps->o.backend == BKEND_XRENDER || ps->o.backend == BKEND_XR_GLX_HYBRID) {
|
||||
if (ps->o.legacy_backend == BKEND_XRENDER ||
|
||||
ps->o.legacy_backend == BKEND_XR_GLX_HYBRID) {
|
||||
uint32_t max_ntraps = to_u32_checked(w->corner_radius);
|
||||
xcb_render_trapezoid_t traps[4 * max_ntraps + 3];
|
||||
uint32_t n = make_rounded_window_shape(
|
||||
|
@ -913,7 +914,7 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
|
|||
factor_center = pct * 8.0 / (1.1 - pct);
|
||||
}
|
||||
|
||||
switch (ps->o.backend) {
|
||||
switch (ps->o.legacy_backend) {
|
||||
case BKEND_XRENDER:
|
||||
case BKEND_XR_GLX_HYBRID: {
|
||||
// Normalize blur kernels
|
||||
|
@ -1043,14 +1044,14 @@ void paint_all(session_t *ps, struct managed_win *t) {
|
|||
}
|
||||
}
|
||||
|
||||
if (BKEND_GLX != ps->o.backend) {
|
||||
if (BKEND_GLX != ps->o.legacy_backend) {
|
||||
ps->tgt_buffer.pict = x_create_picture_with_visual_and_pixmap(
|
||||
&ps->c, ps->c.screen_info->root_visual, ps->tgt_buffer.pixmap,
|
||||
0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (BKEND_XRENDER == ps->o.backend) {
|
||||
if (BKEND_XRENDER == ps->o.legacy_backend) {
|
||||
x_set_picture_clip_region(&ps->c, ps->tgt_picture, 0, 0, ®ion);
|
||||
}
|
||||
|
||||
|
@ -1170,7 +1171,7 @@ void paint_all(session_t *ps, struct managed_win *t) {
|
|||
|
||||
#ifdef CONFIG_OPENGL
|
||||
// If rounded corners backup the region first
|
||||
if (w->corner_radius > 0 && ps->o.backend == BKEND_GLX) {
|
||||
if (w->corner_radius > 0 && ps->o.legacy_backend == BKEND_GLX) {
|
||||
const int16_t x = w->g.x;
|
||||
const int16_t y = w->g.y;
|
||||
auto const wid = to_u16_checked(w->widthb);
|
||||
|
@ -1193,7 +1194,7 @@ void paint_all(session_t *ps, struct managed_win *t) {
|
|||
#ifdef CONFIG_OPENGL
|
||||
// Rounded corners for XRender is implemented inside render()
|
||||
// Round window corners
|
||||
if (w->corner_radius > 0 && ps->o.backend == BKEND_GLX) {
|
||||
if (w->corner_radius > 0 && ps->o.legacy_backend == BKEND_GLX) {
|
||||
auto const wid = to_u16_checked(w->widthb);
|
||||
auto const hei = to_u16_checked(w->heightb);
|
||||
glx_round_corners_dst(ps, w, w->glx_texture_bg, w->g.x,
|
||||
|
@ -1237,7 +1238,7 @@ void paint_all(session_t *ps, struct managed_win *t) {
|
|||
|
||||
auto rwidth = to_u16_checked(ps->root_width);
|
||||
auto rheight = to_u16_checked(ps->root_height);
|
||||
switch (ps->o.backend) {
|
||||
switch (ps->o.legacy_backend) {
|
||||
case BKEND_XRENDER:
|
||||
if (ps->o.monitor_repaint) {
|
||||
// Copy the screen content to a new picture, and highlight the
|
||||
|
@ -1375,7 +1376,7 @@ static bool init_alpha_picts(session_t *ps) {
|
|||
}
|
||||
|
||||
bool init_render(session_t *ps) {
|
||||
if (ps->o.backend == BKEND_DUMMY) {
|
||||
if (ps->o.legacy_backend == BKEND_DUMMY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1400,7 +1401,7 @@ bool init_render(session_t *ps) {
|
|||
}
|
||||
|
||||
// Initialize window GL shader
|
||||
if (BKEND_GLX == ps->o.backend && ps->o.glx_fshader_win_str) {
|
||||
if (BKEND_GLX == ps->o.legacy_backend && ps->o.glx_fshader_win_str) {
|
||||
#ifdef CONFIG_OPENGL
|
||||
if (!glx_load_prog_main(NULL, ps->o.glx_fshader_win_str, &ps->glx_prog_win)) {
|
||||
return false;
|
||||
|
@ -1429,7 +1430,7 @@ bool init_render(session_t *ps) {
|
|||
ccalloc(ps->o.blur_kernel_count, struct x_convolution_kernel *);
|
||||
|
||||
bool ret = false;
|
||||
if (ps->o.backend == BKEND_GLX) {
|
||||
if (ps->o.legacy_backend == BKEND_GLX) {
|
||||
#ifdef CONFIG_OPENGL
|
||||
ret = glx_init_blur(ps);
|
||||
#else
|
||||
|
@ -1465,7 +1466,7 @@ bool init_render(session_t *ps) {
|
|||
}
|
||||
|
||||
// Initialize our rounded corners fragment shader
|
||||
if (ps->o.corner_radius > 0 && ps->o.backend == BKEND_GLX) {
|
||||
if (ps->o.corner_radius > 0 && ps->o.legacy_backend == BKEND_GLX) {
|
||||
#ifdef CONFIG_OPENGL
|
||||
if (!glx_init_rounded_corners(ps)) {
|
||||
log_error("Failed to init rounded corners shader.");
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||
#pragma once
|
||||
|
||||
#include "backend/backend.h"
|
||||
#include "types.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
struct command_builder;
|
||||
struct backend_command;
|
||||
struct layout;
|
||||
struct x_monitors;
|
||||
struct win_option;
|
||||
|
||||
struct command_builder *command_builder_new(void);
|
||||
void command_builder_free(struct command_builder *);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include <picom/types.h>
|
||||
|
||||
typedef struct pixman_region32 region_t;
|
||||
struct layout;
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
#include <stddef.h>
|
||||
#include <uthash.h>
|
||||
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "command_builder.h"
|
||||
#include "common.h"
|
||||
#include "list.h"
|
||||
#include "region.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "win.h"
|
||||
#include "wm.h"
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
#include <pixman.h>
|
||||
#include <stdint.h>
|
||||
#include <xcb/xproto.h>
|
||||
#include "backend/backend.h"
|
||||
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "region.h"
|
||||
#include "types.h"
|
||||
|
||||
struct layer_key {
|
||||
/// Window generation, (see `struct wm::generation` for explanation of what a
|
||||
|
|
|
@ -69,19 +69,19 @@ static void renderer_reallocate_culled_masks(struct renderer *r, size_t capacity
|
|||
|
||||
void renderer_free(struct backend_base *backend, struct renderer *r) {
|
||||
if (r->white_image) {
|
||||
backend->ops->release_image(backend, r->white_image);
|
||||
backend->ops.release_image(backend, r->white_image);
|
||||
}
|
||||
if (r->black_image) {
|
||||
backend->ops->release_image(backend, r->black_image);
|
||||
backend->ops.release_image(backend, r->black_image);
|
||||
}
|
||||
if (r->back_image) {
|
||||
backend->ops->release_image(backend, r->back_image);
|
||||
backend->ops.release_image(backend, r->back_image);
|
||||
}
|
||||
if (r->monitor_repaint_pixel) {
|
||||
backend->ops->release_image(backend, r->monitor_repaint_pixel);
|
||||
backend->ops.release_image(backend, r->monitor_repaint_pixel);
|
||||
}
|
||||
if (r->shadow_blur_context) {
|
||||
backend->ops->destroy_blur_context(backend, r->shadow_blur_context);
|
||||
backend->ops.destroy_blur_context(backend, r->shadow_blur_context);
|
||||
}
|
||||
if (r->shadow_kernel) {
|
||||
free_conv(r->shadow_kernel);
|
||||
|
@ -97,7 +97,7 @@ void renderer_free(struct backend_base *backend, struct renderer *r) {
|
|||
}
|
||||
if (r->monitor_repaint_copy) {
|
||||
for (int i = 0; i < r->max_buffer_age; i++) {
|
||||
backend->ops->release_image(backend, r->monitor_repaint_copy[i]);
|
||||
backend->ops.release_image(backend, r->monitor_repaint_copy[i]);
|
||||
}
|
||||
free(r->monitor_repaint_copy);
|
||||
}
|
||||
|
@ -109,21 +109,21 @@ static bool
|
|||
renderer_init(struct renderer *renderer, struct backend_base *backend,
|
||||
double shadow_radius, struct color shadow_color, bool dithered_present) {
|
||||
auto has_high_precision =
|
||||
backend->ops->is_format_supported(backend, BACKEND_IMAGE_FORMAT_PIXMAP_HIGH);
|
||||
backend->ops.is_format_supported(backend, BACKEND_IMAGE_FORMAT_PIXMAP_HIGH);
|
||||
renderer->format = has_high_precision && dithered_present
|
||||
? BACKEND_IMAGE_FORMAT_PIXMAP_HIGH
|
||||
: BACKEND_IMAGE_FORMAT_PIXMAP;
|
||||
renderer->back_image = NULL;
|
||||
renderer->white_image =
|
||||
backend->ops->new_image(backend, renderer->format, (ivec2){1, 1});
|
||||
if (!renderer->white_image || !backend->ops->clear(backend, renderer->white_image,
|
||||
(struct color){1, 1, 1, 1})) {
|
||||
backend->ops.new_image(backend, renderer->format, (ivec2){1, 1});
|
||||
if (!renderer->white_image || !backend->ops.clear(backend, renderer->white_image,
|
||||
(struct color){1, 1, 1, 1})) {
|
||||
return false;
|
||||
}
|
||||
renderer->black_image =
|
||||
backend->ops->new_image(backend, renderer->format, (ivec2){1, 1});
|
||||
if (!renderer->black_image || !backend->ops->clear(backend, renderer->black_image,
|
||||
(struct color){0, 0, 0, 1})) {
|
||||
backend->ops.new_image(backend, renderer->format, (ivec2){1, 1});
|
||||
if (!renderer->black_image || !backend->ops.clear(backend, renderer->black_image,
|
||||
(struct color){0, 0, 0, 1})) {
|
||||
return false;
|
||||
}
|
||||
renderer->canvas_size = (ivec2){0, 0};
|
||||
|
@ -132,7 +132,7 @@ renderer_init(struct renderer *renderer, struct backend_base *backend,
|
|||
.size = (int)shadow_radius,
|
||||
.deviation = gaussian_kernel_std_for_size(shadow_radius, 0.5 / 256.0),
|
||||
};
|
||||
renderer->shadow_blur_context = backend->ops->create_blur_context(
|
||||
renderer->shadow_blur_context = backend->ops.create_blur_context(
|
||||
backend, BLUR_METHOD_GAUSSIAN, BACKEND_IMAGE_FORMAT_MASK, &args);
|
||||
if (!renderer->shadow_blur_context) {
|
||||
log_error("Failed to create shadow blur context");
|
||||
|
@ -154,7 +154,7 @@ renderer_init(struct renderer *renderer, struct backend_base *backend,
|
|||
}
|
||||
sum_kernel_preprocess(renderer->shadow_kernel);
|
||||
}
|
||||
renderer->max_buffer_age = backend->ops->max_buffer_age + 1;
|
||||
renderer->max_buffer_age = backend->ops.max_buffer_age(backend) + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -176,23 +176,23 @@ renderer_set_root_size(struct renderer *r, struct backend_base *backend, ivec2 r
|
|||
return true;
|
||||
}
|
||||
if (r->back_image) {
|
||||
backend->ops->release_image(backend, r->back_image);
|
||||
backend->ops.release_image(backend, r->back_image);
|
||||
}
|
||||
if (r->back_buffer_copy) {
|
||||
for (int i = 0; i < r->max_buffer_age; i++) {
|
||||
backend->ops->release_image(backend, r->back_buffer_copy[i]);
|
||||
backend->ops.release_image(backend, r->back_buffer_copy[i]);
|
||||
}
|
||||
free(r->back_buffer_copy);
|
||||
r->back_buffer_copy = NULL;
|
||||
}
|
||||
if (r->monitor_repaint_copy) {
|
||||
for (int i = 0; i < r->max_buffer_age; i++) {
|
||||
backend->ops->release_image(backend, r->monitor_repaint_copy[i]);
|
||||
backend->ops.release_image(backend, r->monitor_repaint_copy[i]);
|
||||
}
|
||||
free(r->monitor_repaint_copy);
|
||||
r->monitor_repaint_copy = NULL;
|
||||
}
|
||||
r->back_image = backend->ops->new_image(backend, r->format, root_size);
|
||||
r->back_image = backend->ops.new_image(backend, r->format, root_size);
|
||||
if (r->back_image != NULL) {
|
||||
r->canvas_size = root_size;
|
||||
return true;
|
||||
|
@ -205,16 +205,16 @@ static bool
|
|||
renderer_bind_mask(struct renderer *r, struct backend_base *backend, struct managed_win *w) {
|
||||
ivec2 size = {.width = w->widthb, .height = w->heightb};
|
||||
bool succeeded = false;
|
||||
auto image = backend->ops->new_image(backend, BACKEND_IMAGE_FORMAT_MASK, size);
|
||||
if (!image || !backend->ops->clear(backend, image, (struct color){0, 0, 0, 0})) {
|
||||
auto image = backend->ops.new_image(backend, BACKEND_IMAGE_FORMAT_MASK, size);
|
||||
if (!image || !backend->ops.clear(backend, image, (struct color){0, 0, 0, 0})) {
|
||||
log_error("Failed to create mask image");
|
||||
goto err;
|
||||
}
|
||||
|
||||
auto bound_region_local = win_get_bounding_shape_global_by_val(w);
|
||||
pixman_region32_translate(&bound_region_local, -w->g.x, -w->g.y);
|
||||
succeeded = backend->ops->copy_area(backend, (ivec2){0, 0}, (image_handle)image,
|
||||
r->white_image, &bound_region_local);
|
||||
succeeded = backend->ops.copy_area(backend, (ivec2){0, 0}, (image_handle)image,
|
||||
r->white_image, &bound_region_local);
|
||||
pixman_region32_fini(&bound_region_local);
|
||||
if (!succeeded) {
|
||||
log_error("Failed to fill the mask");
|
||||
|
@ -225,7 +225,7 @@ renderer_bind_mask(struct renderer *r, struct backend_base *backend, struct mana
|
|||
|
||||
err:
|
||||
if (image != NULL) {
|
||||
backend->ops->release_image(backend, image);
|
||||
backend->ops.release_image(backend, image);
|
||||
}
|
||||
return succeeded;
|
||||
}
|
||||
|
@ -243,11 +243,11 @@ image_handle renderer_shadow_from_mask(struct renderer *r, struct backend_base *
|
|||
|
||||
// Apply the properties on the mask image and blit the result into a larger
|
||||
// image, each side larger by `2 * radius` so there is space for blurring.
|
||||
normalized_mask_image = backend->ops->new_image(
|
||||
normalized_mask_image = backend->ops.new_image(
|
||||
backend, BACKEND_IMAGE_FORMAT_MASK,
|
||||
(ivec2){mask_size.width + 2 * radius, mask_size.height + 2 * radius});
|
||||
if (!normalized_mask_image || !backend->ops->clear(backend, normalized_mask_image,
|
||||
(struct color){0, 0, 0, 0})) {
|
||||
if (!normalized_mask_image || !backend->ops.clear(backend, normalized_mask_image,
|
||||
(struct color){0, 0, 0, 0})) {
|
||||
log_error("Failed to create mask image");
|
||||
goto out;
|
||||
}
|
||||
|
@ -276,8 +276,8 @@ image_handle renderer_shadow_from_mask(struct renderer *r, struct backend_base *
|
|||
pixman_region32_init_rect(&target_mask, radius, radius,
|
||||
(unsigned)mask_size.width,
|
||||
(unsigned)mask_size.height);
|
||||
succeeded = backend->ops->blit(backend, (ivec2){radius, radius},
|
||||
normalized_mask_image, &args);
|
||||
succeeded = backend->ops.blit(backend, (ivec2){radius, radius},
|
||||
normalized_mask_image, &args);
|
||||
pixman_region32_fini(&target_mask);
|
||||
if (!succeeded) {
|
||||
log_error("Failed to blit for shadow generation");
|
||||
|
@ -297,7 +297,7 @@ image_handle renderer_shadow_from_mask(struct renderer *r, struct backend_base *
|
|||
(unsigned)(mask_size.width + 2 * radius),
|
||||
(unsigned)(mask_size.height + 2 * radius));
|
||||
succeeded =
|
||||
backend->ops->blur(backend, (ivec2){0, 0}, normalized_mask_image, &args);
|
||||
backend->ops.blur(backend, (ivec2){0, 0}, normalized_mask_image, &args);
|
||||
pixman_region32_fini(&target_mask);
|
||||
if (!succeeded) {
|
||||
log_error("Failed to blur for shadow generation");
|
||||
|
@ -306,19 +306,19 @@ image_handle renderer_shadow_from_mask(struct renderer *r, struct backend_base *
|
|||
}
|
||||
// Finally, we blit with this mask to colorize the shadow
|
||||
succeeded = false;
|
||||
shadow_image = backend->ops->new_image(
|
||||
shadow_image = backend->ops.new_image(
|
||||
backend, BACKEND_IMAGE_FORMAT_PIXMAP,
|
||||
(ivec2){mask_size.width + 2 * radius, mask_size.height + 2 * radius});
|
||||
if (!shadow_image ||
|
||||
!backend->ops->clear(backend, shadow_image, (struct color){0, 0, 0, 0})) {
|
||||
!backend->ops.clear(backend, shadow_image, (struct color){0, 0, 0, 0})) {
|
||||
log_error("Failed to allocate shadow image");
|
||||
goto out;
|
||||
}
|
||||
|
||||
shadow_color_pixel =
|
||||
backend->ops->new_image(backend, BACKEND_IMAGE_FORMAT_PIXMAP, (ivec2){1, 1});
|
||||
backend->ops.new_image(backend, BACKEND_IMAGE_FORMAT_PIXMAP, (ivec2){1, 1});
|
||||
if (!shadow_color_pixel ||
|
||||
!backend->ops->clear(backend, shadow_color_pixel, r->shadow_color)) {
|
||||
!backend->ops.clear(backend, shadow_color_pixel, r->shadow_color)) {
|
||||
log_error("Failed to create shadow color image");
|
||||
goto out;
|
||||
}
|
||||
|
@ -348,19 +348,19 @@ image_handle renderer_shadow_from_mask(struct renderer *r, struct backend_base *
|
|||
};
|
||||
pixman_region32_init_rect(&target_mask, 0, 0, (unsigned)shadow_size.width,
|
||||
(unsigned)shadow_size.height);
|
||||
succeeded = backend->ops->blit(backend, (ivec2){0, 0}, shadow_image, &args);
|
||||
succeeded = backend->ops.blit(backend, (ivec2){0, 0}, shadow_image, &args);
|
||||
pixman_region32_fini(&target_mask);
|
||||
|
||||
out:
|
||||
if (normalized_mask_image) {
|
||||
backend->ops->release_image(backend, normalized_mask_image);
|
||||
backend->ops.release_image(backend, normalized_mask_image);
|
||||
}
|
||||
if (shadow_color_pixel) {
|
||||
backend->ops->release_image(backend, shadow_color_pixel);
|
||||
backend->ops.release_image(backend, shadow_color_pixel);
|
||||
}
|
||||
if (!succeeded && shadow_image) {
|
||||
log_error("Failed to draw shadow image");
|
||||
backend->ops->release_image(backend, shadow_image);
|
||||
backend->ops.release_image(backend, shadow_image);
|
||||
shadow_image = NULL;
|
||||
}
|
||||
return shadow_image;
|
||||
|
@ -368,7 +368,7 @@ out:
|
|||
|
||||
static bool renderer_bind_shadow(struct renderer *r, struct backend_base *backend,
|
||||
struct managed_win *w) {
|
||||
if (backend->ops->quirks(backend) & BACKEND_QUIRK_SLOW_BLUR) {
|
||||
if (backend->ops.quirks(backend) & BACKEND_QUIRK_SLOW_BLUR) {
|
||||
xcb_pixmap_t shadow = XCB_NONE;
|
||||
xcb_render_picture_t pict = XCB_NONE;
|
||||
|
||||
|
@ -379,7 +379,7 @@ static bool renderer_bind_shadow(struct renderer *r, struct backend_base *backen
|
|||
|
||||
auto visual =
|
||||
x_get_visual_for_standard(backend->c, XCB_PICT_STANDARD_ARGB_32);
|
||||
w->shadow_image = backend->ops->bind_pixmap(
|
||||
w->shadow_image = backend->ops.bind_pixmap(
|
||||
backend, shadow, x_get_visual_info(backend->c, visual));
|
||||
} else {
|
||||
if (!w->mask_image && !renderer_bind_mask(r, backend, w)) {
|
||||
|
@ -467,16 +467,16 @@ void renderer_ensure_images_ready(struct renderer *r, struct backend_base *backe
|
|||
bool monitor_repaint) {
|
||||
if (monitor_repaint) {
|
||||
if (!r->monitor_repaint_pixel) {
|
||||
r->monitor_repaint_pixel = backend->ops->new_image(
|
||||
r->monitor_repaint_pixel = backend->ops.new_image(
|
||||
backend, BACKEND_IMAGE_FORMAT_PIXMAP, (ivec2){1, 1});
|
||||
BUG_ON(!r->monitor_repaint_pixel);
|
||||
backend->ops->clear(backend, r->monitor_repaint_pixel,
|
||||
(struct color){.alpha = 0.5, .red = 0.5});
|
||||
backend->ops.clear(backend, r->monitor_repaint_pixel,
|
||||
(struct color){.alpha = 0.5, .red = 0.5});
|
||||
}
|
||||
if (!r->monitor_repaint_copy) {
|
||||
r->monitor_repaint_copy = ccalloc(r->max_buffer_age, image_handle);
|
||||
for (int i = 0; i < r->max_buffer_age; i++) {
|
||||
r->monitor_repaint_copy[i] = backend->ops->new_image(
|
||||
r->monitor_repaint_copy[i] = backend->ops.new_image(
|
||||
backend, BACKEND_IMAGE_FORMAT_PIXMAP,
|
||||
(ivec2){.width = r->canvas_size.width,
|
||||
.height = r->canvas_size.height});
|
||||
|
@ -493,10 +493,10 @@ void renderer_ensure_images_ready(struct renderer *r, struct backend_base *backe
|
|||
if (global_debug_options.consistent_buffer_age && !r->back_buffer_copy) {
|
||||
r->back_buffer_copy = ccalloc(r->max_buffer_age, image_handle);
|
||||
for (int i = 0; i < r->max_buffer_age; i++) {
|
||||
r->back_buffer_copy[i] = backend->ops->new_image(
|
||||
backend, BACKEND_IMAGE_FORMAT_PIXMAP,
|
||||
(ivec2){.width = r->canvas_size.width,
|
||||
.height = r->canvas_size.height});
|
||||
r->back_buffer_copy[i] =
|
||||
backend->ops.new_image(backend, BACKEND_IMAGE_FORMAT_PIXMAP,
|
||||
(ivec2){.width = r->canvas_size.width,
|
||||
.height = r->canvas_size.height});
|
||||
BUG_ON(!r->back_buffer_copy[i]);
|
||||
}
|
||||
}
|
||||
|
@ -554,19 +554,19 @@ bool renderer_render(struct renderer *r, struct backend_base *backend,
|
|||
pixman_region32_init(&damage_region);
|
||||
pixman_region32_copy(&damage_region, &screen_region);
|
||||
ivec2 blur_size = {};
|
||||
if (backend->ops->get_blur_size && blur_context) {
|
||||
backend->ops->get_blur_size(blur_context, &blur_size.width, &blur_size.height);
|
||||
if (backend->ops.get_blur_size && blur_context) {
|
||||
backend->ops.get_blur_size(blur_context, &blur_size.width, &blur_size.height);
|
||||
}
|
||||
auto buffer_age =
|
||||
(use_damage || monitor_repaint) ? backend->ops->buffer_age(backend) : 0;
|
||||
(use_damage || monitor_repaint) ? backend->ops.buffer_age(backend) : 0;
|
||||
if (buffer_age > 0 && global_debug_options.consistent_buffer_age) {
|
||||
int past_frame =
|
||||
(r->frame_index + r->max_buffer_age - buffer_age) % r->max_buffer_age;
|
||||
region_t region;
|
||||
pixman_region32_init_rect(®ion, 0, 0, (unsigned)r->canvas_size.width,
|
||||
(unsigned)r->canvas_size.height);
|
||||
backend->ops->copy_area(backend, (ivec2){}, backend->ops->back_buffer(backend),
|
||||
r->back_buffer_copy[past_frame], ®ion);
|
||||
backend->ops.copy_area(backend, (ivec2){}, backend->ops.back_buffer(backend),
|
||||
r->back_buffer_copy[past_frame], ®ion);
|
||||
pixman_region32_fini(®ion);
|
||||
}
|
||||
if (buffer_age > 0 && (unsigned)buffer_age <= layout_manager_max_buffer_age(lm)) {
|
||||
|
@ -595,17 +595,17 @@ bool renderer_render(struct renderer *r, struct backend_base *backend,
|
|||
xcb_sync_reset_fence(backend->c->c, xsync_fence));
|
||||
}
|
||||
|
||||
if (backend->ops->prepare) {
|
||||
backend->ops->prepare(backend, &layout->commands[0].target_mask);
|
||||
if (backend->ops.prepare) {
|
||||
backend->ops.prepare(backend, &layout->commands[0].target_mask);
|
||||
}
|
||||
|
||||
if (monitor_repaint && buffer_age <= r->max_buffer_age) {
|
||||
// Restore the area of back buffer that was tainted by monitor repaint
|
||||
int past_frame =
|
||||
(r->frame_index + r->max_buffer_age - buffer_age) % r->max_buffer_age;
|
||||
backend->ops->copy_area(backend, (ivec2){}, backend->ops->back_buffer(backend),
|
||||
r->monitor_repaint_copy[past_frame],
|
||||
&r->monitor_repaint_region[past_frame]);
|
||||
backend->ops.copy_area(backend, (ivec2){}, backend->ops.back_buffer(backend),
|
||||
r->monitor_repaint_copy[past_frame],
|
||||
&r->monitor_repaint_region[past_frame]);
|
||||
}
|
||||
|
||||
if (!backend_execute(backend, r->back_image, layout->number_of_commands,
|
||||
|
@ -616,9 +616,9 @@ bool renderer_render(struct renderer *r, struct backend_base *backend,
|
|||
|
||||
if (monitor_repaint) {
|
||||
// Keep a copy of un-tainted back image
|
||||
backend->ops->copy_area(backend, (ivec2){},
|
||||
r->monitor_repaint_copy[r->frame_index],
|
||||
r->back_image, &damage_region);
|
||||
backend->ops.copy_area(backend, (ivec2){},
|
||||
r->monitor_repaint_copy[r->frame_index],
|
||||
r->back_image, &damage_region);
|
||||
pixman_region32_copy(&r->monitor_repaint_region[r->frame_index], &damage_region);
|
||||
|
||||
struct backend_blit_args blit = {
|
||||
|
@ -631,25 +631,23 @@ bool renderer_render(struct renderer *r, struct backend_base *backend,
|
|||
.scale = SCALE_IDENTITY,
|
||||
};
|
||||
log_trace("Blit for monitor repaint");
|
||||
backend->ops->blit(backend, (ivec2){}, r->back_image, &blit);
|
||||
backend->ops.blit(backend, (ivec2){}, r->back_image, &blit);
|
||||
}
|
||||
|
||||
backend->ops->copy_area_quantize(backend, (ivec2){},
|
||||
backend->ops->back_buffer(backend),
|
||||
r->back_image, &damage_region);
|
||||
backend->ops.copy_area_quantize(backend, (ivec2){}, backend->ops.back_buffer(backend),
|
||||
r->back_image, &damage_region);
|
||||
|
||||
if (global_debug_options.consistent_buffer_age) {
|
||||
region_t region;
|
||||
pixman_region32_init_rect(®ion, 0, 0, (unsigned)r->canvas_size.width,
|
||||
(unsigned)r->canvas_size.height);
|
||||
backend->ops->copy_area(backend, (ivec2){},
|
||||
r->back_buffer_copy[r->frame_index],
|
||||
backend->ops->back_buffer(backend), ®ion);
|
||||
backend->ops.copy_area(backend, (ivec2){}, r->back_buffer_copy[r->frame_index],
|
||||
backend->ops.back_buffer(backend), ®ion);
|
||||
pixman_region32_fini(®ion);
|
||||
}
|
||||
|
||||
if (backend->ops->present) {
|
||||
backend->ops->present(backend);
|
||||
if (backend->ops.present && !backend->ops.present(backend)) {
|
||||
log_warn("Failed to present the frame");
|
||||
}
|
||||
|
||||
// "Un-cull" the render commands, so later damage calculation using those commands
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <xcb/sync.h>
|
||||
#include "types.h"
|
||||
|
||||
#include <picom/types.h>
|
||||
|
||||
struct renderer;
|
||||
struct layout_manager;
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
|
||||
#pragma once
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
@ -12,13 +10,13 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <picom/types.h>
|
||||
#include <test.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "compiler.h"
|
||||
#include "log.h"
|
||||
#include "types.h"
|
||||
|
||||
#define ARR_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
|
||||
|
|
15
src/win.c
15
src/win.c
|
@ -15,8 +15,9 @@
|
|||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_renderutil.h>
|
||||
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "atom.h"
|
||||
#include "backend/backend.h"
|
||||
#include "c2.h"
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
|
@ -27,10 +28,6 @@
|
|||
#include "picom.h"
|
||||
#include "region.h"
|
||||
#include "render.h"
|
||||
#include "string_utils.h"
|
||||
#include "transition.h"
|
||||
#include "types.h"
|
||||
#include "uthash_extra.h"
|
||||
#include "utils.h"
|
||||
#include "win_defs.h"
|
||||
#include "wm.h"
|
||||
|
@ -334,7 +331,7 @@ static inline void win_release_pixmap(backend_t *base, struct managed_win *w) {
|
|||
assert(w->win_image);
|
||||
if (w->win_image) {
|
||||
xcb_pixmap_t pixmap = XCB_NONE;
|
||||
pixmap = base->ops->release_image(base, w->win_image);
|
||||
pixmap = base->ops.release_image(base, w->win_image);
|
||||
w->win_image = NULL;
|
||||
// Bypassing win_set_flags, because `w` might have been destroyed
|
||||
w->flags |= WIN_FLAGS_PIXMAP_NONE;
|
||||
|
@ -348,7 +345,7 @@ static inline void win_release_shadow(backend_t *base, struct managed_win *w) {
|
|||
if (w->shadow_image) {
|
||||
assert(w->shadow);
|
||||
xcb_pixmap_t pixmap = XCB_NONE;
|
||||
pixmap = base->ops->release_image(base, w->shadow_image);
|
||||
pixmap = base->ops.release_image(base, w->shadow_image);
|
||||
w->shadow_image = NULL;
|
||||
if (pixmap != XCB_NONE) {
|
||||
xcb_free_pixmap(base->c->c, pixmap);
|
||||
|
@ -359,7 +356,7 @@ static inline void win_release_shadow(backend_t *base, struct managed_win *w) {
|
|||
static inline void win_release_mask(backend_t *base, struct managed_win *w) {
|
||||
if (w->mask_image) {
|
||||
xcb_pixmap_t pixmap = XCB_NONE;
|
||||
pixmap = base->ops->release_image(base, w->mask_image);
|
||||
pixmap = base->ops.release_image(base, w->mask_image);
|
||||
w->mask_image = NULL;
|
||||
if (pixmap != XCB_NONE) {
|
||||
xcb_free_pixmap(base->c->c, pixmap);
|
||||
|
@ -379,7 +376,7 @@ static inline bool win_bind_pixmap(struct backend_base *b, struct managed_win *w
|
|||
return false;
|
||||
}
|
||||
log_debug("New named pixmap for %#010x (%s) : %#010x", w->base.id, w->name, pixmap);
|
||||
w->win_image = b->ops->bind_pixmap(b, pixmap, x_get_visual_info(b->c, w->a.visual));
|
||||
w->win_image = b->ops.bind_pixmap(b, pixmap, x_get_visual_info(b->c, w->a.visual));
|
||||
if (!w->win_image) {
|
||||
log_error("Failed to bind pixmap");
|
||||
xcb_free_pixmap(b->c->c, pixmap);
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
#include <xcb/render.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include <backend/backend.h>
|
||||
|
||||
#include "uthash_extra.h"
|
||||
#include <picom/backend.h>
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "c2.h"
|
||||
#include "compiler.h"
|
||||
|
@ -17,8 +16,6 @@
|
|||
#include "region.h"
|
||||
#include "render.h"
|
||||
#include "script.h"
|
||||
#include "transition.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "win_defs.h"
|
||||
#include "x.h"
|
||||
|
|
7
src/x.c
7
src/x.c
|
@ -832,11 +832,18 @@ void x_create_convolution_kernel(const conv *kernel, double center,
|
|||
buf[1] = DOUBLE_TO_XFIXED(kernel->h);
|
||||
|
||||
double sum = center;
|
||||
bool has_neg = false;
|
||||
for (int i = 0; i < kernel->w * kernel->h; i++) {
|
||||
if (i == kernel->w * kernel->h / 2) {
|
||||
// Ignore center
|
||||
continue;
|
||||
}
|
||||
sum += kernel->data[i];
|
||||
if (kernel->data[i] < 0 && !has_neg) {
|
||||
has_neg = true;
|
||||
log_warn("A X convolution kernel with negative values may not "
|
||||
"work properly.");
|
||||
}
|
||||
}
|
||||
|
||||
// Note for floating points a / b != a * (1 / b), but this shouldn't have any real
|
||||
|
|
15
src/x.h
15
src/x.h
|
@ -43,21 +43,6 @@ typedef struct winprop_info {
|
|||
uint32_t length;
|
||||
} winprop_info_t;
|
||||
|
||||
struct xvisual_info {
|
||||
/// Bit depth of the red component
|
||||
int red_size;
|
||||
/// Bit depth of the green component
|
||||
int green_size;
|
||||
/// Bit depth of the blue component
|
||||
int blue_size;
|
||||
/// Bit depth of the alpha component
|
||||
int alpha_size;
|
||||
/// The depth of X visual
|
||||
int visual_depth;
|
||||
|
||||
xcb_visualid_t visual;
|
||||
};
|
||||
|
||||
enum pending_reply_action {
|
||||
PENDING_REPLY_ACTION_IGNORE,
|
||||
PENDING_REPLY_ACTION_ABORT,
|
||||
|
|
Loading…
Add table
Reference in a new issue