mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-29 05:40:12 -04:00
Compare commits
78 commits
2ca8a4c136
...
3bfcfeabbd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bfcfeabbd | ||
|
|
879243e370 | ||
|
|
989cffe70d | ||
|
|
3e08e3be4a | ||
|
|
91f4890ec2 | ||
|
|
74ce6c22a5 | ||
|
|
0b58bddf13 | ||
|
|
3d36ab9211 | ||
|
|
d786e07899 | ||
|
|
6d63871f05 | ||
|
|
19c5d22beb | ||
|
|
06275103f2 | ||
|
|
03e7966650 | ||
|
|
5529aae3e6 | ||
|
|
6e1c8748ff | ||
|
|
d8fb7adcf0 | ||
|
|
c2d9ae2142 | ||
|
|
6978509f64 | ||
|
|
2252854297 | ||
|
|
dde07b6840 | ||
|
|
406aa5f7f5 | ||
|
|
2ec4012559 | ||
|
|
d039ad8da3 | ||
|
|
3f0d338643 | ||
|
|
60d72724cd | ||
|
|
7cb3393e75 | ||
|
|
26c1476827 | ||
|
|
138210f01c | ||
|
|
845a7a581d | ||
|
|
108d94f798 | ||
|
|
aaf82ee332 | ||
|
|
d1c88e9497 | ||
|
|
3e88a79e6f | ||
|
|
b2d09cdee9 | ||
|
|
35eba5f2fe | ||
|
|
a91f96b391 | ||
|
|
6fee3623e4 | ||
|
|
7f6d66ea62 | ||
|
|
54374b6fe6 | ||
|
|
dd7f543189 | ||
|
|
d7ae9a866b | ||
|
|
462046ffdc | ||
|
|
bd566225ea | ||
|
|
b62c6878e1 | ||
|
|
fd069ad4f2 | ||
|
|
5e5842cb1a | ||
|
|
cdd2c7e006 | ||
|
|
905465b0fa | ||
|
|
102a6bd415 | ||
|
|
06aacb2a6f | ||
|
|
0166fd9eb7 | ||
|
|
423afc3fc9 | ||
|
|
122310a2de | ||
|
|
b799ffc6ae | ||
|
|
e95117b700 | ||
|
|
1a18e47efa | ||
|
|
bbd9a49bdf | ||
|
|
7bf5ff4c02 | ||
|
|
b0c886ec77 | ||
|
|
7431d840d0 | ||
|
|
bb1f8673b3 | ||
|
|
ad1b2f2819 | ||
|
|
812675ba34 | ||
|
|
7392b3313a | ||
|
|
07e92fb868 | ||
|
|
12316417b0 | ||
|
|
dd3c63f5e6 | ||
|
|
c8b7600adc | ||
|
|
51a78cb0ed | ||
| 1beb25a1c8 | |||
|
|
2f2c0dfcc6 | ||
|
|
47a90d6f1a | ||
|
|
db5e9ca04c | ||
|
|
efb17980a8 | ||
|
|
be5e266211 | ||
|
|
80c7e0f772 | ||
|
|
ccec4116b3 | ||
|
|
04dc72e8c1 |
78 changed files with 1771 additions and 497 deletions
|
|
@ -41,9 +41,10 @@ tasks:
|
|||
cd wlroots/build-gcc/tinywl
|
||||
sudo modprobe vkms
|
||||
udevadm settle
|
||||
card="/dev/dri/$(ls /sys/devices/faux/vkms/drm/ | grep ^card)"
|
||||
export WLR_BACKENDS=drm
|
||||
export WLR_RENDERER=pixman
|
||||
export WLR_DRM_DEVICES=/dev/dri/by-path/platform-vkms-card
|
||||
export WLR_DRM_DEVICES="$card"
|
||||
export UBSAN_OPTIONS=halt_on_error=1
|
||||
sudo chmod ugo+rw /dev/dri/by-path/platform-vkms-card
|
||||
sudo chmod ugo+rw "$card"
|
||||
sudo -E seatd-launch -- ./tinywl -s 'kill $PPID' || [ $? = 143 ]
|
||||
|
|
|
|||
|
|
@ -485,5 +485,10 @@ bool wlr_backend_commit(struct wlr_backend *backend,
|
|||
output_apply_commit(state->output, &state->base);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < states_len; i++) {
|
||||
const struct wlr_backend_output_state *state = &states[i];
|
||||
output_send_commit_event(state->output, &state->base);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,6 +186,10 @@ static uint8_t convert_cta861_eotf(enum wlr_color_transfer_function tf) {
|
|||
return 2;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
abort(); // unsupported
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||
abort(); // unsupported
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
abort(); // unsupported
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1717,7 +1717,11 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
|
|||
size_t edid_len = 0;
|
||||
uint8_t *edid = get_drm_prop_blob(drm->fd,
|
||||
wlr_conn->id, wlr_conn->props.edid, &edid_len);
|
||||
parse_edid(wlr_conn, edid_len, edid);
|
||||
if (edid_len > 0) {
|
||||
parse_edid(wlr_conn, edid_len, edid);
|
||||
} else {
|
||||
wlr_log(WLR_DEBUG, "Connector has no EDID");
|
||||
}
|
||||
free(edid);
|
||||
|
||||
char *subconnector = NULL;
|
||||
|
|
|
|||
|
|
@ -367,7 +367,10 @@ void wlr_session_close_file(struct wlr_session *session,
|
|||
}
|
||||
|
||||
assert(wl_list_empty(&dev->events.change.listener_list));
|
||||
assert(wl_list_empty(&dev->events.remove.listener_list));
|
||||
// TODO: assert that the "remove" listener list is empty as well. Listeners
|
||||
// will typically call wlr_session_close_file() in response, and
|
||||
// wl_signal_emit_mutable() installs two phantom listeners, so we'd count
|
||||
// these two.
|
||||
|
||||
close(dev->fd);
|
||||
wl_list_remove(&dev->link);
|
||||
|
|
@ -516,8 +519,6 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
break;
|
||||
}
|
||||
|
||||
bool is_boot_vga = false;
|
||||
|
||||
const char *path = udev_list_entry_get_name(entry);
|
||||
struct udev_device *dev = udev_device_new_from_syspath(session->udev, path);
|
||||
if (!dev) {
|
||||
|
|
@ -533,14 +534,20 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
continue;
|
||||
}
|
||||
|
||||
// This is owned by 'dev', so we don't need to free it
|
||||
struct udev_device *pci =
|
||||
udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
|
||||
bool is_primary = false;
|
||||
const char *boot_display = udev_device_get_sysattr_value(dev, "boot_display");
|
||||
if (boot_display && strcmp(boot_display, "1") == 0) {
|
||||
is_primary = true;
|
||||
} else {
|
||||
// This is owned by 'dev', so we don't need to free it
|
||||
struct udev_device *pci =
|
||||
udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
|
||||
|
||||
if (pci) {
|
||||
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
|
||||
if (id && strcmp(id, "1") == 0) {
|
||||
is_boot_vga = true;
|
||||
if (pci) {
|
||||
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
|
||||
if (id && strcmp(id, "1") == 0) {
|
||||
is_primary = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -554,7 +561,7 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
udev_device_unref(dev);
|
||||
|
||||
ret[i] = wlr_dev;
|
||||
if (is_boot_vga) {
|
||||
if (is_primary) {
|
||||
struct wlr_device *tmp = ret[0];
|
||||
ret[0] = ret[i];
|
||||
ret[i] = tmp;
|
||||
|
|
|
|||
|
|
@ -55,14 +55,6 @@ struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *wlr_backe
|
|||
static int dispatch_events(int fd, uint32_t mask, void *data) {
|
||||
struct wlr_wl_backend *wl = data;
|
||||
|
||||
if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
|
||||
if (mask & WL_EVENT_ERROR) {
|
||||
wlr_log(WLR_ERROR, "Failed to read from remote Wayland display");
|
||||
}
|
||||
wlr_backend_destroy(&wl->backend);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
if (mask & WL_EVENT_READABLE) {
|
||||
count = wl_display_dispatch(wl->remote_display);
|
||||
|
|
@ -75,6 +67,18 @@ static int dispatch_events(int fd, uint32_t mask, void *data) {
|
|||
wl_display_flush(wl->remote_display);
|
||||
}
|
||||
|
||||
// Make sure we've consumed all data before disconnecting due to hangup,
|
||||
// so that we process any wl_display.error events
|
||||
if (!(mask & WL_EVENT_READABLE) && (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR))) {
|
||||
if (mask & WL_EVENT_ERROR) {
|
||||
wlr_log(WLR_ERROR, "Failed to read from remote Wayland display");
|
||||
} else {
|
||||
wlr_log(WLR_DEBUG, "Disconnected from remote Wayland display");
|
||||
}
|
||||
wlr_backend_destroy(&wl->backend);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count < 0) {
|
||||
wlr_log(WLR_ERROR, "Failed to dispatch remote Wayland display");
|
||||
wlr_backend_destroy(&wl->backend);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ enum wlr_color_transform_type {
|
|||
COLOR_TRANSFORM_INVERSE_EOTF,
|
||||
COLOR_TRANSFORM_LCMS2,
|
||||
COLOR_TRANSFORM_LUT_3X1D,
|
||||
COLOR_TRANSFORM_PIPELINE,
|
||||
};
|
||||
|
||||
struct wlr_color_transform {
|
||||
|
|
@ -39,6 +40,13 @@ struct wlr_color_transform_lut_3x1d {
|
|||
size_t dim;
|
||||
};
|
||||
|
||||
struct wlr_color_transform_pipeline {
|
||||
struct wlr_color_transform base;
|
||||
|
||||
struct wlr_color_transform **transforms;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
void wlr_color_transform_init(struct wlr_color_transform *tr,
|
||||
enum wlr_color_transform_type type);
|
||||
|
||||
|
|
@ -72,12 +80,6 @@ struct wlr_color_transform_inverse_eotf *wlr_color_transform_inverse_eotf_from_b
|
|||
struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
||||
struct wlr_color_transform *tr);
|
||||
|
||||
/**
|
||||
* Evaluate a 3x1D LUT color transform for a given RGB triplet.
|
||||
*/
|
||||
void color_transform_lut_3x1d_eval(struct wlr_color_transform_lut_3x1d *tr,
|
||||
float out[static 3], const float in[static 3]);
|
||||
|
||||
/**
|
||||
* Obtain primaries values from a well-known primaries name.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -153,6 +153,8 @@ enum wlr_vk_texture_transform {
|
|||
WLR_VK_TEXTURE_TRANSFORM_IDENTITY = 0,
|
||||
WLR_VK_TEXTURE_TRANSFORM_SRGB = 1,
|
||||
WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ = 2,
|
||||
WLR_VK_TEXTURE_TRANSFORM_GAMMA22 = 3,
|
||||
WLR_VK_TEXTURE_TRANSFORM_BT1886 = 4,
|
||||
};
|
||||
|
||||
enum wlr_vk_shader_source {
|
||||
|
|
@ -167,6 +169,8 @@ enum wlr_vk_output_transform {
|
|||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB = 1,
|
||||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ = 2,
|
||||
WLR_VK_OUTPUT_TRANSFORM_LUT3D = 3,
|
||||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22 = 4,
|
||||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886 = 5,
|
||||
};
|
||||
|
||||
struct wlr_vk_pipeline_key {
|
||||
|
|
@ -199,11 +203,20 @@ struct wlr_vk_render_format_setup {
|
|||
VkPipeline output_pipe_srgb;
|
||||
VkPipeline output_pipe_pq;
|
||||
VkPipeline output_pipe_lut3d;
|
||||
VkPipeline output_pipe_gamma22;
|
||||
VkPipeline output_pipe_bt1886;
|
||||
|
||||
struct wlr_vk_renderer *renderer;
|
||||
struct wl_list pipelines; // struct wlr_vk_pipeline.link
|
||||
};
|
||||
|
||||
// Final output framebuffer and image view
|
||||
struct wlr_vk_render_buffer_out {
|
||||
VkImageView image_view;
|
||||
VkFramebuffer framebuffer;
|
||||
bool transitioned;
|
||||
};
|
||||
|
||||
// Renderer-internal represenation of an wlr_buffer imported for rendering.
|
||||
struct wlr_vk_render_buffer {
|
||||
struct wlr_buffer *wlr_buffer;
|
||||
|
|
@ -215,36 +228,40 @@ struct wlr_vk_render_buffer {
|
|||
uint32_t mem_count;
|
||||
VkImage image;
|
||||
|
||||
// Framebuffer and image view for rendering directly onto the buffer image,
|
||||
// without any color transform.
|
||||
struct {
|
||||
struct wlr_vk_render_buffer_out out;
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
} linear;
|
||||
|
||||
// Framebuffer and image view for rendering directly onto the buffer image.
|
||||
// This requires that the image support an _SRGB VkFormat, and does
|
||||
// not work with color transforms.
|
||||
struct {
|
||||
struct wlr_vk_render_buffer_out out;
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
VkImageView image_view;
|
||||
VkFramebuffer framebuffer;
|
||||
bool transitioned;
|
||||
} srgb;
|
||||
|
||||
// Framebuffer, image view, and blending image to render indirectly
|
||||
// onto the buffer image. This works for general image types and permits
|
||||
// color transforms.
|
||||
struct {
|
||||
struct wlr_vk_render_buffer_out out;
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
|
||||
VkImageView image_view;
|
||||
VkFramebuffer framebuffer;
|
||||
bool transitioned;
|
||||
|
||||
VkImage blend_image;
|
||||
VkImageView blend_image_view;
|
||||
VkDeviceMemory blend_memory;
|
||||
VkDescriptorSet blend_descriptor_set;
|
||||
struct wlr_vk_descriptor_pool *blend_attachment_pool;
|
||||
bool blend_transitioned;
|
||||
} plain;
|
||||
} two_pass;
|
||||
};
|
||||
|
||||
bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
const struct wlr_dmabuf_attributes *dmabuf, bool srgb);
|
||||
bool vulkan_setup_two_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
const struct wlr_dmabuf_attributes *dmabuf);
|
||||
|
||||
struct wlr_vk_command_buffer {
|
||||
|
|
@ -396,12 +413,14 @@ struct wlr_vk_render_pass {
|
|||
struct wlr_render_pass base;
|
||||
struct wlr_vk_renderer *renderer;
|
||||
struct wlr_vk_render_buffer *render_buffer;
|
||||
struct wlr_vk_render_buffer_out *render_buffer_out;
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
struct wlr_vk_command_buffer *command_buffer;
|
||||
struct rect_union updated_region;
|
||||
VkPipeline bound_pipeline;
|
||||
float projection[9];
|
||||
bool failed;
|
||||
bool srgb_pathway; // if false, rendering via intermediate blending buffer
|
||||
bool two_pass; // rendering via intermediate blending buffer
|
||||
struct wlr_color_transform *color_transform;
|
||||
|
||||
bool has_primaries;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ void output_defer_present(struct wlr_output *output, struct wlr_output_event_pre
|
|||
|
||||
bool output_prepare_commit(struct wlr_output *output, const struct wlr_output_state *state);
|
||||
void output_apply_commit(struct wlr_output *output, const struct wlr_output_state *state);
|
||||
void output_send_commit_event(struct wlr_output *output, const struct wlr_output_state *state);
|
||||
|
||||
void output_state_get_buffer_src_box(const struct wlr_output_state *state,
|
||||
struct wlr_fbox *out);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ enum wlr_color_transfer_function {
|
|||
WLR_COLOR_TRANSFER_FUNCTION_SRGB = 1 << 0,
|
||||
WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ = 1 << 1,
|
||||
WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR = 1 << 2,
|
||||
WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 = 1 << 3,
|
||||
WLR_COLOR_TRANSFER_FUNCTION_BT1886 = 1 << 4,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -139,6 +141,13 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_inverse_eotf(
|
|||
struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
|
||||
const uint16_t *r, const uint16_t *g, const uint16_t *b);
|
||||
|
||||
/**
|
||||
* Initialize a color transformation to apply a sequence of color transforms
|
||||
* one after another.
|
||||
*/
|
||||
struct wlr_color_transform *wlr_color_transform_init_pipeline(
|
||||
struct wlr_color_transform **transforms, size_t len);
|
||||
|
||||
/**
|
||||
* Increase the reference count of the color transform by 1.
|
||||
*/
|
||||
|
|
@ -150,4 +159,10 @@ struct wlr_color_transform *wlr_color_transform_ref(struct wlr_color_transform *
|
|||
*/
|
||||
void wlr_color_transform_unref(struct wlr_color_transform *tr);
|
||||
|
||||
/**
|
||||
* Evaluate a color transform for a given RGB triplet.
|
||||
*/
|
||||
void wlr_color_transform_eval(struct wlr_color_transform *tr,
|
||||
float out[static 3], const float in[static 3]);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,8 +31,9 @@ struct wlr_render_timer;
|
|||
struct wlr_buffer_pass_options {
|
||||
/* Timer to measure the duration of the render pass */
|
||||
struct wlr_render_timer *timer;
|
||||
/* Color transform to apply to the output of the render pass,
|
||||
* leave NULL to indicate sRGB/no custom transform */
|
||||
/* Color transform to apply to the output of the render pass.
|
||||
* Leave NULL to indicate the default transform (Gamma 2.2 encoding for
|
||||
* sRGB monitors) */
|
||||
struct wlr_color_transform *color_transform;
|
||||
/** Primaries describing the color volume of the destination buffer */
|
||||
const struct wlr_color_primaries *primaries;
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@
|
|||
#ifndef WLR_TYPES_WLR_COLOR_MANAGEMENT_V1_H
|
||||
#define WLR_TYPES_WLR_COLOR_MANAGEMENT_V1_H
|
||||
|
||||
#include <wayland-server.h>
|
||||
#include <wlr/render/color.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-protocols/color-management-v1-enum.h>
|
||||
|
||||
#include "color-management-v1-protocol.h"
|
||||
#include <wlr/render/color.h>
|
||||
|
||||
struct wlr_surface;
|
||||
|
||||
|
|
@ -58,6 +58,10 @@ struct wlr_color_manager_v1_options {
|
|||
struct wlr_color_manager_v1 {
|
||||
struct wl_global *global;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wlr_color_manager_v1_features features;
|
||||
|
||||
|
|
@ -89,4 +93,30 @@ void wlr_color_manager_v1_set_surface_preferred_image_description(
|
|||
struct wlr_color_manager_v1 *manager, struct wlr_surface *surface,
|
||||
const struct wlr_image_description_v1_data *data);
|
||||
|
||||
/**
|
||||
* Convert a protocol transfer function to enum wlr_color_transfer_function.
|
||||
* Aborts if there is no matching wlroots entry.
|
||||
*/
|
||||
enum wlr_color_transfer_function
|
||||
wlr_color_manager_v1_transfer_function_to_wlr(enum wp_color_manager_v1_transfer_function tf);
|
||||
|
||||
/**
|
||||
* Convert an enum wlr_color_transfer_function value into a protocol transfer function.
|
||||
*/
|
||||
enum wp_color_manager_v1_transfer_function
|
||||
wlr_color_manager_v1_transfer_function_from_wlr(enum wlr_color_transfer_function tf);
|
||||
|
||||
/**
|
||||
* Convert a protocol named primaries to enum wlr_color_named_primaries.
|
||||
* Aborts if there is no matching wlroots entry.
|
||||
*/
|
||||
enum wlr_color_named_primaries
|
||||
wlr_color_manager_v1_primaries_to_wlr(enum wp_color_manager_v1_primaries primaries);
|
||||
|
||||
/**
|
||||
* Convert an enum wlr_color_named_primaries value into protocol primaries.
|
||||
*/
|
||||
enum wp_color_manager_v1_primaries
|
||||
wlr_color_manager_v1_primaries_from_wlr(enum wlr_color_named_primaries primaries);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -10,10 +10,9 @@
|
|||
#define WLR_TYPES_WLR_COLOR_REPRESENTATION_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-protocols/color-representation-v1-enum.h>
|
||||
#include <wlr/render/color.h>
|
||||
|
||||
#include "color-representation-v1-protocol.h"
|
||||
|
||||
struct wlr_surface;
|
||||
|
||||
// Supported coefficients and range are always paired together
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#define WLR_TYPES_WLR_CONTENT_TYPE_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include "content-type-v1-protocol.h"
|
||||
#include <wayland-protocols/content-type-v1-enum.h>
|
||||
|
||||
struct wlr_surface;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#define WLR_TYPES_WLR_CURSOR_SHAPE_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include "cursor-shape-v1-protocol.h"
|
||||
#include <wayland-protocols/cursor-shape-v1-enum.h>
|
||||
|
||||
/**
|
||||
* Manager for the cursor-shape-v1 protocol.
|
||||
|
|
|
|||
|
|
@ -12,6 +12,12 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
|
||||
/**
|
||||
* Deprecated: this protocol is legacy and superseded by ext-data-control-v1.
|
||||
* The implementation will be dropped in a future wlroots version.
|
||||
*
|
||||
* Consider using `wlr_ext_data_control_manager_v1` as a replacement.
|
||||
*/
|
||||
struct wlr_data_control_manager_v1 {
|
||||
struct wl_global *global;
|
||||
struct wl_list devices; // wlr_data_control_device_v1.link
|
||||
|
|
|
|||
|
|
@ -62,8 +62,6 @@ struct wlr_drm_lease_connector_v1 {
|
|||
|
||||
struct wlr_output *output;
|
||||
struct wlr_drm_lease_device_v1 *device;
|
||||
/** NULL if no client is currently leasing this connector */
|
||||
struct wlr_drm_lease_v1 *active_lease;
|
||||
|
||||
struct wl_list link; // wlr_drm_lease_device_v1.connectors
|
||||
|
||||
|
|
@ -93,9 +91,6 @@ struct wlr_drm_lease_v1 {
|
|||
|
||||
struct wlr_drm_lease_device_v1 *device;
|
||||
|
||||
struct wlr_drm_lease_connector_v1 **connectors;
|
||||
size_t n_connectors;
|
||||
|
||||
struct wl_list link; // wlr_drm_lease_device_v1.leases
|
||||
|
||||
void *data;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ struct wlr_ext_data_control_manager_v1 {
|
|||
struct wl_signal new_device; // wlr_ext_data_control_device_v1
|
||||
} events;
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_ext_data_control_device_v1 {
|
||||
|
|
@ -33,9 +35,11 @@ struct wlr_ext_data_control_device_v1 {
|
|||
struct wl_resource *selection_offer_resource; // current selection offer
|
||||
struct wl_resource *primary_selection_offer_resource; // current primary selection offer
|
||||
|
||||
struct wl_listener seat_destroy;
|
||||
struct wl_listener seat_set_selection;
|
||||
struct wl_listener seat_set_primary_selection;
|
||||
struct {
|
||||
struct wl_listener seat_destroy;
|
||||
struct wl_listener seat_set_selection;
|
||||
struct wl_listener seat_set_primary_selection;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_ext_data_control_manager_v1 *wlr_ext_data_control_manager_v1_create(
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
#define WLR_TYPES_WLR_EXT_IMAGE_COPY_CAPTURE_V1_H
|
||||
|
||||
#include <pixman.h>
|
||||
#include <wayland-server.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <wayland-protocols/ext-image-copy-capture-v1-enum.h>
|
||||
#include <time.h>
|
||||
#include "ext-image-copy-capture-v1-protocol.h"
|
||||
|
||||
struct wlr_renderer;
|
||||
|
||||
|
|
|
|||
28
include/wlr/types/wlr_fixes.h
Normal file
28
include/wlr/types/wlr_fixes.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||
* future consistency of this API.
|
||||
*/
|
||||
#ifndef WLR_USE_UNSTABLE
|
||||
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||
#endif
|
||||
|
||||
#ifndef WLR_TYPES_WLR_FIXES_H
|
||||
#define WLR_TYPES_WLR_FIXES_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
struct wlr_fixes {
|
||||
struct wl_global *global;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_fixes *wlr_fixes_create(struct wl_display *display, uint32_t version);
|
||||
|
||||
#endif
|
||||
|
|
@ -10,6 +10,11 @@ struct wlr_gamma_control_manager_v1 {
|
|||
struct wl_global *global;
|
||||
struct wl_list controls; // wlr_gamma_control_v1.link
|
||||
|
||||
// Fallback to use when an struct wlr_output doesn't support gamma LUTs.
|
||||
// Can be used to apply gamma LUTs via a struct wlr_renderer. Leave zero to
|
||||
// indicate that the fallback is unsupported.
|
||||
size_t fallback_gamma_size;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
struct wl_signal set_gamma; // struct wlr_gamma_control_manager_v1_set_gamma_event
|
||||
|
|
@ -49,6 +54,8 @@ struct wlr_gamma_control_v1 *wlr_gamma_control_manager_v1_get_control(
|
|||
struct wlr_gamma_control_manager_v1 *manager, struct wlr_output *output);
|
||||
bool wlr_gamma_control_v1_apply(struct wlr_gamma_control_v1 *gamma_control,
|
||||
struct wlr_output_state *output_state);
|
||||
struct wlr_color_transform *wlr_gamma_control_v1_get_color_transform(
|
||||
struct wlr_gamma_control_v1 *gamma_control);
|
||||
void wlr_gamma_control_v1_send_failed_and_destroy(struct wlr_gamma_control_v1 *gamma_control);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -48,10 +48,10 @@ struct wlr_input_method_v2 {
|
|||
struct wl_list link;
|
||||
|
||||
struct {
|
||||
struct wl_signal commit; // struct wlr_input_method_v2
|
||||
struct wl_signal commit;
|
||||
struct wl_signal new_popup_surface; // struct wlr_input_popup_surface_v2
|
||||
struct wl_signal grab_keyboard; // struct wlr_input_method_keyboard_grab_v2
|
||||
struct wl_signal destroy; // struct wlr_input_method_v2
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
|
|
@ -94,8 +94,8 @@ struct wlr_input_method_manager_v2 {
|
|||
struct wl_list input_methods; // struct wlr_input_method_v2.link
|
||||
|
||||
struct {
|
||||
struct wl_signal input_method; // struct wlr_input_method_v2
|
||||
struct wl_signal destroy; // struct wlr_input_method_manager_v2
|
||||
struct wl_signal new_input_method; // struct wlr_input_method_v2
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -267,6 +267,7 @@ struct wlr_output {
|
|||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
struct wlr_output_image_description image_description_value;
|
||||
struct wlr_color_transform *color_transform;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-protocols/pointer-constraints-unstable-v1-enum.h>
|
||||
#include <pixman.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include "pointer-constraints-unstable-v1-protocol.h"
|
||||
|
||||
struct wlr_seat;
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ struct wlr_scene_output_layout;
|
|||
struct wlr_presentation;
|
||||
struct wlr_linux_dmabuf_v1;
|
||||
struct wlr_gamma_control_manager_v1;
|
||||
struct wlr_color_manager_v1;
|
||||
struct wlr_output_state;
|
||||
|
||||
typedef bool (*wlr_scene_buffer_point_accepts_input_func_t)(
|
||||
|
|
@ -102,11 +103,13 @@ struct wlr_scene {
|
|||
// May be NULL
|
||||
struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1;
|
||||
struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1;
|
||||
struct wlr_color_manager_v1 *color_manager_v1;
|
||||
|
||||
struct {
|
||||
struct wl_listener linux_dmabuf_v1_destroy;
|
||||
struct wl_listener gamma_control_manager_v1_destroy;
|
||||
struct wl_listener gamma_control_manager_v1_set_gamma;
|
||||
struct wl_listener color_manager_v1_destroy;
|
||||
|
||||
enum wlr_scene_debug_damage_option debug_damage_option;
|
||||
bool direct_scanout;
|
||||
|
|
@ -249,6 +252,11 @@ struct wlr_scene_output {
|
|||
|
||||
bool gamma_lut_changed;
|
||||
struct wlr_gamma_control_v1 *gamma_lut;
|
||||
struct wlr_color_transform *gamma_lut_color_transform;
|
||||
|
||||
struct wlr_color_transform *prev_gamma_lut_color_transform;
|
||||
struct wlr_color_transform *prev_supplied_color_transform;
|
||||
struct wlr_color_transform *prev_combined_color_transform;
|
||||
|
||||
struct wl_listener output_commit;
|
||||
struct wl_listener output_damage;
|
||||
|
|
@ -366,6 +374,13 @@ void wlr_scene_set_linux_dmabuf_v1(struct wlr_scene *scene,
|
|||
void wlr_scene_set_gamma_control_manager_v1(struct wlr_scene *scene,
|
||||
struct wlr_gamma_control_manager_v1 *gamma_control);
|
||||
|
||||
/**
|
||||
* Handles color_management_v1 feedback for all surfaces in the scene.
|
||||
*
|
||||
* Asserts that a struct wlr_color_manager_v1 hasn't already been set for the scene.
|
||||
*/
|
||||
void wlr_scene_set_color_manager_v1(struct wlr_scene *scene, struct wlr_color_manager_v1 *manager);
|
||||
|
||||
/**
|
||||
* Add a node displaying nothing but its children.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -14,6 +14,13 @@
|
|||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/util/box.h>
|
||||
|
||||
/**
|
||||
* Deprecated: this protocol is deprecated and superseded by ext-image-copy-capture-v1.
|
||||
* The implementation will be dropped in a future wlroots version.
|
||||
*
|
||||
* Consider using `wlr_ext_image_capture_source_v1` instead.
|
||||
*/
|
||||
|
||||
struct wlr_screencopy_manager_v1 {
|
||||
struct wl_global *global;
|
||||
struct wl_list frames; // wlr_screencopy_frame_v1.link
|
||||
|
|
|
|||
|
|
@ -10,10 +10,9 @@
|
|||
#define WLR_TYPES_WLR_TABLET_V2_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-protocols/tablet-v2-enum.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
|
||||
#include "tablet-v2-protocol.h"
|
||||
|
||||
/* This can probably be even lower,the tools don't have a lot of buttons */
|
||||
#define WLR_TABLET_V2_TOOL_BUTTONS_CAP 16
|
||||
|
||||
|
|
|
|||
|
|
@ -11,11 +11,9 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <wayland-protocols/tearing-control-v1-enum.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
|
||||
#include "tearing-control-v1-protocol.h"
|
||||
|
||||
struct wlr_tearing_control_v1 {
|
||||
struct wl_client *client;
|
||||
struct wl_list link;
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@
|
|||
#define WLR_TYPES_WLR_XDG_SHELL_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-protocols/xdg-shell-enum.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include "xdg-shell-protocol.h"
|
||||
|
||||
struct wlr_xdg_shell {
|
||||
struct wl_global *global;
|
||||
|
|
|
|||
48
include/wlr/util/rectpack.h
Normal file
48
include/wlr/util/rectpack.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||
* future consistency of this API.
|
||||
*/
|
||||
#ifndef WLR_USE_UNSTABLE
|
||||
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||
#endif
|
||||
|
||||
#ifndef WLR_UTIL_RECTPACK_H
|
||||
#define WLR_UTIL_RECTPACK_H
|
||||
|
||||
#include <pixman.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
|
||||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/edges.h>
|
||||
|
||||
struct wlr_layer_surface_v1;
|
||||
|
||||
struct wlr_rectpack_rules {
|
||||
// If true, the corresponding side will be stretched to take all available area
|
||||
bool grow_width, grow_height;
|
||||
};
|
||||
|
||||
/**
|
||||
* Place a rectangle within bounds so that it doesn't intersect with the
|
||||
* exclusive region.
|
||||
*
|
||||
* exclusive may be NULL.
|
||||
*
|
||||
* Returns false if there's not enough space or on memory allocation error.
|
||||
*/
|
||||
bool wlr_rectpack_place(const struct wlr_box *bounds, pixman_region32_t *exclusive,
|
||||
const struct wlr_box *box, struct wlr_rectpack_rules *rules, struct wlr_box *out);
|
||||
|
||||
/**
|
||||
* Place a struct wlr_layer_surface_v1 within bounds so that it doesn't
|
||||
* intersect with the exclusive region. If the layer surface has exclusive zone,
|
||||
* the corresponding area will be added to the exclusive region.
|
||||
*
|
||||
* Returns false if there's not enough space or on memory allocation error, in
|
||||
* which case the exclusive region is left intact.
|
||||
*/
|
||||
bool wlr_rectpack_place_wlr_layer_surface_v1(const struct wlr_box *bounds,
|
||||
pixman_region32_t *exclusive, struct wlr_layer_surface_v1 *surface, struct wlr_box *out);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -164,6 +164,7 @@ struct wlr_xwm {
|
|||
struct wl_listener drop_focus_destroy;
|
||||
};
|
||||
|
||||
// xwm_create takes ownership of wm_fd and will close it under all circumstances.
|
||||
struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland, int wm_fd);
|
||||
|
||||
void xwm_destroy(struct wlr_xwm *xwm);
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ internal_features = {
|
|||
internal_config = configuration_data()
|
||||
|
||||
wayland_kwargs = {
|
||||
'version': '>=1.23.1',
|
||||
'version': '>=1.24.0',
|
||||
'fallback': 'wayland',
|
||||
'default_options': [
|
||||
'tests=false',
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
wayland_protos = dependency('wayland-protocols',
|
||||
version: '>=1.43',
|
||||
version: '>=1.44',
|
||||
fallback: 'wayland-protocols',
|
||||
default_options: ['tests=false'],
|
||||
)
|
||||
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
|
||||
wlr_deps += wayland_protos
|
||||
|
||||
wayland_scanner_dep = dependency('wayland-scanner',
|
||||
kwargs: wayland_kwargs,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
<request name="capture_output">
|
||||
<description summary="capture a frame from an output">
|
||||
Capture the next frame of a an entire output.
|
||||
Capture the next frame of an entire output.
|
||||
</description>
|
||||
<arg name="frame" type="new_id" interface="zwlr_export_dmabuf_frame_v1"/>
|
||||
<arg name="overlay_cursor" type="int"
|
||||
|
|
@ -136,7 +136,7 @@
|
|||
<arg name="stride" type="uint"
|
||||
summary="line size in bytes"/>
|
||||
<arg name="plane_index" type="uint"
|
||||
summary="index of the the plane the data in the object applies to"/>
|
||||
summary="index of the plane the data in the object applies to"/>
|
||||
</event>
|
||||
|
||||
<event name="ready">
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
</description>
|
||||
</request>
|
||||
|
||||
<event name="finished">
|
||||
<event name="finished" type="destructor">
|
||||
<description summary="the compositor has finished with the toplevel manager">
|
||||
This event indicates that the compositor is done sending events to the
|
||||
zwlr_foreign_toplevel_manager_v1. The server will destroy the object
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
tables. At any time the compositor can send a failed event indicating that
|
||||
this object is no longer valid.
|
||||
|
||||
There must always be at most one gamma control object per output, which
|
||||
There can only be at most one gamma control object per output, which
|
||||
has exclusive access to this particular output. When the gamma control
|
||||
object is destroyed, the gamma table is restored to its original value.
|
||||
</description>
|
||||
|
|
|
|||
|
|
@ -156,8 +156,8 @@
|
|||
not assume that the name is a reflection of an underlying DRM
|
||||
connector, X11 connection, etc.
|
||||
|
||||
If the compositor implements the xdg-output protocol and this head is
|
||||
enabled, the xdg_output.name event must report the same name.
|
||||
If this head matches a wl_output, the wl_output.name event must report
|
||||
the same name.
|
||||
|
||||
The name event is sent after a wlr_output_head object is created. This
|
||||
event is only sent once per object, and the name does not change over
|
||||
|
|
@ -176,8 +176,8 @@
|
|||
the make, model, serial of the underlying DRM connector or the display
|
||||
name of the underlying X11 connection, etc.
|
||||
|
||||
If the compositor implements xdg-output and this head is enabled,
|
||||
the xdg_output.description must report the same description.
|
||||
If this head matches a wl_output, the wl_output.description event must
|
||||
report the same name.
|
||||
|
||||
The description event is sent after a wlr_output_head object is created.
|
||||
This event is only sent once per object, and the description does not
|
||||
|
|
@ -191,6 +191,10 @@
|
|||
This event describes the physical size of the head. This event is only
|
||||
sent if the head has a physical size (e.g. is not a projector or a
|
||||
virtual device).
|
||||
|
||||
The physical size event is sent after a wlr_output_head object is created. This
|
||||
event is only sent once per object, and the physical size does not change over
|
||||
the lifetime of the wlr_output_head object.
|
||||
</description>
|
||||
<arg name="width" type="int" summary="width in millimeters of the output"/>
|
||||
<arg name="height" type="int" summary="height in millimeters of the output"/>
|
||||
|
|
@ -264,9 +268,6 @@
|
|||
<description summary="head manufacturer">
|
||||
This event describes the manufacturer of the head.
|
||||
|
||||
This must report the same make as the wl_output interface does in its
|
||||
geometry event.
|
||||
|
||||
Together with the model and serial_number events the purpose is to
|
||||
allow clients to recognize heads from previous sessions and for example
|
||||
load head-specific configurations back.
|
||||
|
|
@ -278,6 +279,10 @@
|
|||
identify the head by available information from other events but should
|
||||
be aware that there is an increased risk of false positives.
|
||||
|
||||
If sent, the make event is sent after a wlr_output_head object is
|
||||
created and only sent once per object. The make does not change over
|
||||
the lifetime of the wlr_output_head object.
|
||||
|
||||
It is not recommended to display the make string in UI to users. For
|
||||
that the string provided by the description event should be preferred.
|
||||
</description>
|
||||
|
|
@ -288,9 +293,6 @@
|
|||
<description summary="head model">
|
||||
This event describes the model of the head.
|
||||
|
||||
This must report the same model as the wl_output interface does in its
|
||||
geometry event.
|
||||
|
||||
Together with the make and serial_number events the purpose is to
|
||||
allow clients to recognize heads from previous sessions and for example
|
||||
load head-specific configurations back.
|
||||
|
|
@ -302,6 +304,10 @@
|
|||
identify the head by available information from other events but should
|
||||
be aware that there is an increased risk of false positives.
|
||||
|
||||
If sent, the model event is sent after a wlr_output_head object is
|
||||
created and only sent once per object. The model does not change over
|
||||
the lifetime of the wlr_output_head object.
|
||||
|
||||
It is not recommended to display the model string in UI to users. For
|
||||
that the string provided by the description event should be preferred.
|
||||
</description>
|
||||
|
|
@ -323,6 +329,10 @@
|
|||
available information from other events but should be aware that there
|
||||
is an increased risk of false positives.
|
||||
|
||||
If sent, the serial number event is sent after a wlr_output_head object
|
||||
is created and only sent once per object. The serial number does not
|
||||
change over the lifetime of the wlr_output_head object.
|
||||
|
||||
It is not recommended to display the serial_number string in UI to
|
||||
users. For that the string provided by the description event should be
|
||||
preferred.
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@
|
|||
|
||||
<request name="get_output_power">
|
||||
<description summary="get a power management for an output">
|
||||
Create a output power management mode control that can be used to
|
||||
Create an output power management mode control that can be used to
|
||||
adjust the power management mode for a given output.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zwlr_output_power_v1"/>
|
||||
|
|
@ -79,7 +79,7 @@
|
|||
</enum>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="invalid_mode" value="1" summary="inexistent power save mode"/>
|
||||
<entry name="invalid_mode" value="1" summary="nonexistent power save mode"/>
|
||||
</enum>
|
||||
|
||||
<request name="set_mode">
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@
|
|||
supported buffer type. The "buffer_done" event is sent afterwards to
|
||||
indicate that all supported buffer types have been enumerated. The client
|
||||
will then be able to send a "copy" request. If the capture is successful,
|
||||
the compositor will send a "flags" followed by a "ready" event.
|
||||
the compositor will send a "flags" event followed by a "ready" event.
|
||||
|
||||
For objects version 2 or lower, wl_shm buffers are always supported, ie.
|
||||
the "buffer" event is guaranteed to be sent.
|
||||
|
|
@ -114,12 +114,12 @@
|
|||
|
||||
<request name="copy">
|
||||
<description summary="copy the frame">
|
||||
Copy the frame to the supplied buffer. The buffer must have a the
|
||||
Copy the frame to the supplied buffer. The buffer must have the
|
||||
correct size, see zwlr_screencopy_frame_v1.buffer and
|
||||
zwlr_screencopy_frame_v1.linux_dmabuf. The buffer needs to have a
|
||||
supported format.
|
||||
|
||||
If the frame is successfully copied, a "flags" and a "ready" events are
|
||||
If the frame is successfully copied, "flags" and "ready" events are
|
||||
sent. Otherwise, a "failed" event is sent.
|
||||
</description>
|
||||
<arg name="buffer" type="object" interface="wl_buffer"/>
|
||||
|
|
@ -147,8 +147,7 @@
|
|||
<event name="ready">
|
||||
<description summary="indicates frame is available for reading">
|
||||
Called as soon as the frame is copied, indicating it is available
|
||||
for reading. This event includes the time at which presentation happened
|
||||
at.
|
||||
for reading. This event includes the time at which the presentation took place.
|
||||
|
||||
The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples,
|
||||
each component being an unsigned 32-bit value. Whole seconds are in
|
||||
|
|
|
|||
32
release.sh
Executable file
32
release.sh
Executable file
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/sh -eu
|
||||
|
||||
prev=$(git describe --tags --abbrev=0)
|
||||
next=$(meson rewrite kwargs info project / | jq -r '.kwargs["project#/"].version')
|
||||
|
||||
case "$next" in
|
||||
*-dev)
|
||||
echo "This is a development version"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$prev" = "$next" ]; then
|
||||
echo "Version not bumped in meson.build"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! git diff-index --quiet HEAD -- meson.build; then
|
||||
echo "meson.build not committed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
shortlog="$(git shortlog --no-merges "$prev..")"
|
||||
(echo "wlroots $next"; echo ""; echo "$shortlog") | git tag "$next" -ase -F -
|
||||
|
||||
prefix=wlroots-$next
|
||||
archive=$prefix.tar.gz
|
||||
git archive --prefix="$prefix/" -o "$archive" "$next"
|
||||
gpg --output "$archive".sig --detach-sig "$archive"
|
||||
|
||||
git push --follow-tags
|
||||
glab release create "$next" "$archive" "$archive.sig" --notes ""
|
||||
|
|
@ -97,7 +97,6 @@ static struct wlr_gbm_buffer *create_buffer(struct wlr_gbm_allocator *alloc,
|
|||
}
|
||||
wlr_buffer_init(&buffer->base, &buffer_impl, width, height);
|
||||
buffer->gbm_bo = bo;
|
||||
wl_list_insert(&alloc->buffers, &buffer->link);
|
||||
|
||||
if (!export_gbm_bo(bo, &buffer->dmabuf)) {
|
||||
free(buffer);
|
||||
|
|
@ -112,6 +111,8 @@ static struct wlr_gbm_buffer *create_buffer(struct wlr_gbm_allocator *alloc,
|
|||
buffer->dmabuf.modifier = fallback_modifier;
|
||||
}
|
||||
|
||||
wl_list_insert(&alloc->buffers, &buffer->link);
|
||||
|
||||
char *format_name = drmGetFormatName(buffer->dmabuf.format);
|
||||
char *modifier_name = drmGetFormatModifierName(buffer->dmabuf.modifier);
|
||||
wlr_log(WLR_DEBUG, "Allocated %dx%d GBM buffer "
|
||||
|
|
|
|||
130
render/color.c
130
render/color.c
|
|
@ -62,6 +62,33 @@ struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
|
|||
return &tx->base;
|
||||
}
|
||||
|
||||
struct wlr_color_transform *wlr_color_transform_init_pipeline(
|
||||
struct wlr_color_transform **transforms, size_t len) {
|
||||
assert(len > 0);
|
||||
|
||||
struct wlr_color_transform **copy = calloc(len, sizeof(copy[0]));
|
||||
if (copy == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_color_transform_pipeline *tx = calloc(1, sizeof(*tx));
|
||||
if (!tx) {
|
||||
free(copy);
|
||||
return NULL;
|
||||
}
|
||||
wlr_color_transform_init(&tx->base, COLOR_TRANSFORM_PIPELINE);
|
||||
|
||||
// TODO: flatten nested pipeline transforms
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
copy[i] = wlr_color_transform_ref(transforms[i]);
|
||||
}
|
||||
|
||||
tx->transforms = copy;
|
||||
tx->len = len;
|
||||
|
||||
return &tx->base;
|
||||
}
|
||||
|
||||
static void color_transform_destroy(struct wlr_color_transform *tr) {
|
||||
switch (tr->type) {
|
||||
case COLOR_TRANSFORM_INVERSE_EOTF:
|
||||
|
|
@ -73,6 +100,14 @@ static void color_transform_destroy(struct wlr_color_transform *tr) {
|
|||
struct wlr_color_transform_lut_3x1d *lut_3x1d = color_transform_lut_3x1d_from_base(tr);
|
||||
free(lut_3x1d->lut_3x1d);
|
||||
break;
|
||||
case COLOR_TRANSFORM_PIPELINE:;
|
||||
struct wlr_color_transform_pipeline *pipeline =
|
||||
wl_container_of(tr, pipeline, base);
|
||||
for (size_t i = 0; i < pipeline->len; i++) {
|
||||
wlr_color_transform_unref(pipeline->transforms[i]);
|
||||
}
|
||||
free(pipeline->transforms);
|
||||
break;
|
||||
}
|
||||
wlr_addon_set_finish(&tr->addons);
|
||||
free(tr);
|
||||
|
|
@ -108,8 +143,67 @@ struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
|||
return lut_3x1d;
|
||||
}
|
||||
|
||||
static float srgb_eval_inverse_eotf(float x) {
|
||||
// See https://www.w3.org/Graphics/Color/srgb
|
||||
if (x <= 0.0031308) {
|
||||
return 12.92 * x;
|
||||
} else {
|
||||
return 1.055 * powf(x, 1.0 / 2.4) - 0.055;
|
||||
}
|
||||
}
|
||||
|
||||
static float st2084_pq_eval_inverse_eotf(float x) {
|
||||
// H.273 TransferCharacteristics code point 16
|
||||
float c1 = 0.8359375;
|
||||
float c2 = 18.8515625;
|
||||
float c3 = 18.6875;
|
||||
float m = 78.84375;
|
||||
float n = 0.1593017578125;
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
}
|
||||
if (x > 1) {
|
||||
x = 1;
|
||||
}
|
||||
float pow_n = powf(x, n);
|
||||
return powf((c1 + c2 * pow_n) / (1 + c3 * pow_n), m);
|
||||
}
|
||||
|
||||
static float bt1886_eval_inverse_eotf(float x) {
|
||||
float lb = powf(0.0001, 1.0 / 2.4);
|
||||
float lw = powf(1.0, 1.0 / 2.4);
|
||||
float a = powf(lw - lb, 2.4);
|
||||
float b = lb / (lw - lb);
|
||||
return powf(x / a, 1.0 / 2.4) - b;
|
||||
}
|
||||
|
||||
static float transfer_function_eval_inverse_eotf(
|
||||
enum wlr_color_transfer_function tf, float x) {
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
return srgb_eval_inverse_eotf(x);
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
return st2084_pq_eval_inverse_eotf(x);
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
return x;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||
return powf(x, 1.0 / 2.2);
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
return bt1886_eval_inverse_eotf(x);
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
static void color_transform_inverse_eotf_eval(
|
||||
struct wlr_color_transform_inverse_eotf *tr,
|
||||
float out[static 3], const float in[static 3]) {
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
out[i] = transfer_function_eval_inverse_eotf(tr->tf, in[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static float lut_1d_get(const uint16_t *lut, size_t len, size_t i) {
|
||||
if (i > len) {
|
||||
if (i >= len) {
|
||||
i = len - 1;
|
||||
}
|
||||
return (float) lut[i] / UINT16_MAX;
|
||||
|
|
@ -125,13 +219,38 @@ static float lut_1d_eval(const uint16_t *lut, size_t len, float x) {
|
|||
return a * (1 - frac_part) + b * frac_part;
|
||||
}
|
||||
|
||||
void color_transform_lut_3x1d_eval(struct wlr_color_transform_lut_3x1d *tr,
|
||||
static void color_transform_lut_3x1d_eval(struct wlr_color_transform_lut_3x1d *tr,
|
||||
float out[static 3], const float in[static 3]) {
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
out[i] = lut_1d_eval(&tr->lut_3x1d[tr->dim * i], tr->dim, in[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void wlr_color_transform_eval(struct wlr_color_transform *tr,
|
||||
float out[static 3], const float in[static 3]) {
|
||||
switch (tr->type) {
|
||||
case COLOR_TRANSFORM_INVERSE_EOTF:
|
||||
color_transform_inverse_eotf_eval(wlr_color_transform_inverse_eotf_from_base(tr), out, in);
|
||||
break;
|
||||
case COLOR_TRANSFORM_LCMS2:
|
||||
color_transform_lcms2_eval(color_transform_lcms2_from_base(tr), out, in);
|
||||
break;
|
||||
case COLOR_TRANSFORM_LUT_3X1D:
|
||||
color_transform_lut_3x1d_eval(color_transform_lut_3x1d_from_base(tr), out, in);
|
||||
break;
|
||||
case COLOR_TRANSFORM_PIPELINE:;
|
||||
struct wlr_color_transform_pipeline *pipeline =
|
||||
wl_container_of(tr, pipeline, base);
|
||||
float color[3];
|
||||
memcpy(color, in, sizeof(color));
|
||||
for (size_t i = 0; i < pipeline->len; i++) {
|
||||
wlr_color_transform_eval(pipeline->transforms[i], color, color);
|
||||
}
|
||||
memcpy(out, color, sizeof(color));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void wlr_color_primaries_from_named(struct wlr_color_primaries *out,
|
||||
enum wlr_color_named_primaries named) {
|
||||
switch (named) {
|
||||
|
|
@ -202,6 +321,13 @@ void wlr_color_transfer_function_get_default_luminance(enum wlr_color_transfer_f
|
|||
.reference = 203,
|
||||
};
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
*lum = (struct wlr_color_luminances){
|
||||
.min = 0.01,
|
||||
.max = 100,
|
||||
.reference = 100,
|
||||
};
|
||||
break;
|
||||
default:
|
||||
*lum = (struct wlr_color_luminances){
|
||||
.min = 0.2,
|
||||
|
|
|
|||
|
|
@ -57,10 +57,7 @@ static void convert_pixman_box_to_vk_rect(const pixman_box32_t *box, VkRect2D *r
|
|||
}
|
||||
|
||||
static float color_to_linear(float non_linear) {
|
||||
// See https://www.w3.org/Graphics/Color/srgb
|
||||
return (non_linear > 0.04045) ?
|
||||
pow((non_linear + 0.055) / 1.055, 2.4) :
|
||||
non_linear / 12.92;
|
||||
return pow(non_linear, 2.2);
|
||||
}
|
||||
|
||||
static float color_to_linear_premult(float non_linear, float alpha) {
|
||||
|
|
@ -175,7 +172,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
assert(stage_cb != NULL);
|
||||
renderer->stage.cb = NULL;
|
||||
|
||||
if (!pass->srgb_pathway) {
|
||||
if (pass->two_pass) {
|
||||
// Apply output shader to map blend image to actual output image
|
||||
vkCmdNextSubpass(render_cb->vk, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
|
|
@ -227,9 +224,9 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
if (pass->color_transform && pass->color_transform->type != COLOR_TRANSFORM_INVERSE_EOTF) {
|
||||
pipeline = render_buffer->plain.render_setup->output_pipe_lut3d;
|
||||
pipeline = render_buffer->two_pass.render_setup->output_pipe_lut3d;
|
||||
} else {
|
||||
enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_SRGB;
|
||||
enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
if (pass->color_transform && pass->color_transform->type == COLOR_TRANSFORM_INVERSE_EOTF) {
|
||||
struct wlr_color_transform_inverse_eotf *inverse_eotf =
|
||||
wlr_color_transform_inverse_eotf_from_base(pass->color_transform);
|
||||
|
|
@ -238,13 +235,19 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
pipeline = render_buffer->plain.render_setup->output_pipe_identity;
|
||||
pipeline = render_buffer->two_pass.render_setup->output_pipe_identity;
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
pipeline = render_buffer->plain.render_setup->output_pipe_srgb;
|
||||
pipeline = render_buffer->two_pass.render_setup->output_pipe_srgb;
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
pipeline = render_buffer->plain.render_setup->output_pipe_pq;
|
||||
pipeline = render_buffer->two_pass.render_setup->output_pipe_pq;
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||
pipeline = render_buffer->two_pass.render_setup->output_pipe_gamma22;
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
pipeline = render_buffer->two_pass.render_setup->output_pipe_bt1886;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -268,7 +271,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
lut_ds = renderer->output_ds_lut3d_dummy;
|
||||
}
|
||||
VkDescriptorSet ds[] = {
|
||||
render_buffer->plain.blend_descriptor_set, // set 0
|
||||
render_buffer->two_pass.blend_descriptor_set, // set 0
|
||||
lut_ds, // set 1
|
||||
};
|
||||
size_t ds_len = sizeof(ds) / sizeof(ds[0]);
|
||||
|
|
@ -398,30 +401,26 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
|
||||
// also add acquire/release barriers for the current render buffer
|
||||
VkImageLayout src_layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
if (pass->srgb_pathway) {
|
||||
if (!render_buffer->srgb.transitioned) {
|
||||
src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||
render_buffer->srgb.transitioned = true;
|
||||
}
|
||||
} else {
|
||||
if (!render_buffer->plain.transitioned) {
|
||||
src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||
render_buffer->plain.transitioned = true;
|
||||
}
|
||||
if (!pass->render_buffer_out->transitioned) {
|
||||
src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||
pass->render_buffer_out->transitioned = true;
|
||||
}
|
||||
|
||||
if (pass->two_pass) {
|
||||
// The render pass changes the blend image layout from
|
||||
// color attachment to read only, so on each frame, before
|
||||
// the render pass starts, we change it back
|
||||
VkImageLayout blend_src_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
if (!render_buffer->plain.blend_transitioned) {
|
||||
if (!render_buffer->two_pass.blend_transitioned) {
|
||||
blend_src_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
render_buffer->plain.blend_transitioned = true;
|
||||
render_buffer->two_pass.blend_transitioned = true;
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier blend_acq_barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = render_buffer->plain.blend_image,
|
||||
.image = render_buffer->two_pass.blend_image,
|
||||
.oldLayout = blend_src_layout,
|
||||
.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
|
|
@ -618,7 +617,7 @@ error:
|
|||
|
||||
static void render_pass_mark_box_updated(struct wlr_vk_render_pass *pass,
|
||||
const struct wlr_box *box) {
|
||||
if (pass->srgb_pathway) {
|
||||
if (!pass->two_pass) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -678,11 +677,8 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass,
|
|||
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, proj);
|
||||
wlr_matrix_multiply(matrix, pass->projection, matrix);
|
||||
|
||||
struct wlr_vk_render_format_setup *setup = pass->srgb_pathway ?
|
||||
pass->render_buffer->srgb.render_setup :
|
||||
pass->render_buffer->plain.render_setup;
|
||||
struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline(
|
||||
setup,
|
||||
pass->render_setup,
|
||||
&(struct wlr_vk_pipeline_key) {
|
||||
.source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR,
|
||||
.layout = { .ycbcr_format = NULL },
|
||||
|
|
@ -783,7 +779,7 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
|
|||
|
||||
enum wlr_color_transfer_function tf = options->transfer_function;
|
||||
if (tf == 0) {
|
||||
tf = WLR_COLOR_TRANSFER_FUNCTION_SRGB;
|
||||
tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
}
|
||||
|
||||
bool srgb_image_view = false;
|
||||
|
|
@ -803,13 +799,16 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
|
|||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ;
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_GAMMA22;
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_BT1886;
|
||||
break;
|
||||
}
|
||||
|
||||
struct wlr_vk_render_format_setup *setup = pass->srgb_pathway ?
|
||||
pass->render_buffer->srgb.render_setup :
|
||||
pass->render_buffer->plain.render_setup;
|
||||
struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline(
|
||||
setup,
|
||||
pass->render_setup,
|
||||
&(struct wlr_vk_pipeline_key) {
|
||||
.source = WLR_VK_SHADER_SOURCE_TEXTURE,
|
||||
.layout = {
|
||||
|
|
@ -850,7 +849,8 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
|
|||
}
|
||||
|
||||
float luminance_multiplier = 1;
|
||||
if (tf != WLR_COLOR_TRANSFER_FUNCTION_SRGB) {
|
||||
if (tf != WLR_COLOR_TRANSFER_FUNCTION_SRGB
|
||||
&& tf != WLR_COLOR_TRANSFER_FUNCTION_GAMMA22) {
|
||||
struct wlr_color_luminances src_lum, srgb_lum;
|
||||
wlr_color_transfer_function_get_default_luminance(tf, &src_lum);
|
||||
wlr_color_transfer_function_get_default_luminance(
|
||||
|
|
@ -964,19 +964,6 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
|||
*ds = VK_NULL_HANDLE;
|
||||
*ds_pool = NULL;
|
||||
|
||||
struct wlr_color_transform_lcms2 *tr_lcms2 = NULL;
|
||||
struct wlr_color_transform_lut_3x1d *tr_lut_3x1d = NULL;
|
||||
switch (tr->type) {
|
||||
case COLOR_TRANSFORM_INVERSE_EOTF:
|
||||
abort(); // unreachable
|
||||
case COLOR_TRANSFORM_LCMS2:
|
||||
tr_lcms2 = color_transform_lcms2_from_base(tr);
|
||||
break;
|
||||
case COLOR_TRANSFORM_LUT_3X1D:
|
||||
tr_lut_3x1d = color_transform_lut_3x1d_from_base(tr);
|
||||
break;
|
||||
}
|
||||
|
||||
// R32G32B32 is not a required Vulkan format
|
||||
// TODO: use it when available
|
||||
VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
|
|
@ -1074,11 +1061,7 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
|||
b_index * sample_range,
|
||||
};
|
||||
float rgb_out[3];
|
||||
if (tr_lcms2 != NULL) {
|
||||
color_transform_lcms2_eval(tr_lcms2, rgb_out, rgb_in);
|
||||
} else {
|
||||
color_transform_lut_3x1d_eval(tr_lut_3x1d, rgb_out, rgb_in);
|
||||
}
|
||||
wlr_color_transform_eval(tr, rgb_out, rgb_in);
|
||||
|
||||
dst[dst_offset] = rgb_out[0];
|
||||
dst[dst_offset + 1] = rgb_out[1];
|
||||
|
|
@ -1177,29 +1160,68 @@ static const struct wlr_addon_interface vk_color_transform_impl = {
|
|||
|
||||
struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *renderer,
|
||||
struct wlr_vk_render_buffer *buffer, const struct wlr_buffer_pass_options *options) {
|
||||
bool using_srgb_pathway;
|
||||
uint32_t inv_eotf;
|
||||
if (options != NULL && options->color_transform != NULL) {
|
||||
using_srgb_pathway = false;
|
||||
if (options->color_transform->type == COLOR_TRANSFORM_INVERSE_EOTF) {
|
||||
struct wlr_color_transform_inverse_eotf *tr =
|
||||
wlr_color_transform_inverse_eotf_from_base(options->color_transform);
|
||||
inv_eotf = tr->tf;
|
||||
} else {
|
||||
// Color transform is not an inverse EOTF
|
||||
inv_eotf = 0;
|
||||
}
|
||||
} else {
|
||||
// This is the default when unspecified
|
||||
inv_eotf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
}
|
||||
|
||||
if (!get_color_transform(options->color_transform, renderer)) {
|
||||
bool using_linear_pathway = inv_eotf == WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
bool using_srgb_pathway = inv_eotf == WLR_COLOR_TRANSFER_FUNCTION_SRGB &&
|
||||
buffer->srgb.out.framebuffer != VK_NULL_HANDLE;
|
||||
bool using_two_pass_pathway = !using_linear_pathway && !using_srgb_pathway;
|
||||
|
||||
if (using_linear_pathway && !buffer->linear.out.image_view) {
|
||||
struct wlr_dmabuf_attributes attribs;
|
||||
wlr_buffer_get_dmabuf(buffer->wlr_buffer, &attribs);
|
||||
if (!vulkan_setup_one_pass_framebuffer(buffer, &attribs, false)) {
|
||||
wlr_log(WLR_ERROR, "Failed to set up blend image");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (using_two_pass_pathway) {
|
||||
if (options != NULL && options->color_transform != NULL &&
|
||||
!get_color_transform(options->color_transform, renderer)) {
|
||||
/* Try to create a new color transform */
|
||||
if (!vk_color_transform_create(renderer, options->color_transform)) {
|
||||
wlr_log(WLR_ERROR, "Failed to create color transform");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Use srgb pathway if it is the default/has already been set up
|
||||
using_srgb_pathway = buffer->srgb.framebuffer != VK_NULL_HANDLE;
|
||||
|
||||
if (!buffer->two_pass.out.image_view) {
|
||||
struct wlr_dmabuf_attributes attribs;
|
||||
wlr_buffer_get_dmabuf(buffer->wlr_buffer, &attribs);
|
||||
if (!vulkan_setup_two_pass_framebuffer(buffer, &attribs)) {
|
||||
wlr_log(WLR_ERROR, "Failed to set up blend image");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!using_srgb_pathway && !buffer->plain.image_view) {
|
||||
struct wlr_dmabuf_attributes attribs;
|
||||
wlr_buffer_get_dmabuf(buffer->wlr_buffer, &attribs);
|
||||
if (!vulkan_setup_plain_framebuffer(buffer, &attribs)) {
|
||||
wlr_log(WLR_ERROR, "Failed to set up blend image");
|
||||
return NULL;
|
||||
}
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
struct wlr_vk_render_buffer_out *buffer_out;
|
||||
if (using_two_pass_pathway) {
|
||||
render_setup = buffer->two_pass.render_setup;
|
||||
buffer_out = &buffer->two_pass.out;
|
||||
} else if (using_srgb_pathway) {
|
||||
render_setup = buffer->srgb.render_setup;
|
||||
buffer_out = &buffer->srgb.out;
|
||||
} else if (using_linear_pathway) {
|
||||
render_setup = buffer->linear.render_setup;
|
||||
buffer_out = &buffer->linear.out;
|
||||
} else {
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
struct wlr_vk_render_pass *pass = calloc(1, sizeof(*pass));
|
||||
|
|
@ -1209,7 +1231,7 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
|
|||
|
||||
wlr_render_pass_init(&pass->base, &render_pass_impl);
|
||||
pass->renderer = renderer;
|
||||
pass->srgb_pathway = using_srgb_pathway;
|
||||
pass->two_pass = using_two_pass_pathway;
|
||||
if (options != NULL && options->color_transform != NULL) {
|
||||
pass->color_transform = wlr_color_transform_ref(options->color_transform);
|
||||
}
|
||||
|
|
@ -1257,14 +1279,9 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
|
|||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||
.renderArea = rect,
|
||||
.clearValueCount = 0,
|
||||
.renderPass = render_setup->render_pass,
|
||||
.framebuffer = buffer_out->framebuffer,
|
||||
};
|
||||
if (pass->srgb_pathway) {
|
||||
rp_info.renderPass = buffer->srgb.render_setup->render_pass;
|
||||
rp_info.framebuffer = buffer->srgb.framebuffer;
|
||||
} else {
|
||||
rp_info.renderPass = buffer->plain.render_setup->render_pass;
|
||||
rp_info.framebuffer = buffer->plain.framebuffer;
|
||||
}
|
||||
vkCmdBeginRenderPass(cb->vk, &rp_info, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vkCmdSetViewport(cb->vk, 0, 1, &(VkViewport){
|
||||
|
|
@ -1279,6 +1296,8 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
|
|||
|
||||
wlr_buffer_lock(buffer->wlr_buffer);
|
||||
pass->render_buffer = buffer;
|
||||
pass->render_buffer_out = buffer_out;
|
||||
pass->render_setup = render_setup;
|
||||
pass->command_buffer = cb;
|
||||
return pass;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,59 +66,72 @@ static struct wlr_vk_descriptor_pool *alloc_ds(
|
|||
struct wl_list *pool_list, size_t *last_pool_size) {
|
||||
VkResult res;
|
||||
|
||||
bool found = false;
|
||||
struct wlr_vk_descriptor_pool *pool;
|
||||
wl_list_for_each(pool, pool_list, link) {
|
||||
if (pool->free > 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) { // create new pool
|
||||
pool = calloc(1, sizeof(*pool));
|
||||
if (!pool) {
|
||||
wlr_log_errno(WLR_ERROR, "allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t count = 2 * (*last_pool_size);
|
||||
if (!count) {
|
||||
count = start_descriptor_pool_size;
|
||||
}
|
||||
|
||||
pool->free = count;
|
||||
VkDescriptorPoolSize pool_size = {
|
||||
.descriptorCount = count,
|
||||
.type = type,
|
||||
};
|
||||
|
||||
VkDescriptorPoolCreateInfo dpool_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.maxSets = count,
|
||||
.poolSizeCount = 1,
|
||||
.pPoolSizes = &pool_size,
|
||||
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
|
||||
};
|
||||
|
||||
res = vkCreateDescriptorPool(renderer->dev->dev, &dpool_info, NULL,
|
||||
&pool->pool);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateDescriptorPool", res);
|
||||
free(pool);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*last_pool_size = count;
|
||||
wl_list_insert(pool_list, &pool->link);
|
||||
}
|
||||
|
||||
VkDescriptorSetAllocateInfo ds_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.descriptorSetCount = 1,
|
||||
.pSetLayouts = layout,
|
||||
.descriptorPool = pool->pool,
|
||||
};
|
||||
|
||||
struct wlr_vk_descriptor_pool *pool;
|
||||
wl_list_for_each(pool, pool_list, link) {
|
||||
if (pool->free > 0) {
|
||||
ds_info.descriptorPool = pool->pool;
|
||||
res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
|
||||
switch (res) {
|
||||
case VK_ERROR_FRAGMENTED_POOL:
|
||||
case VK_ERROR_OUT_OF_POOL_MEMORY:
|
||||
// Descriptor sets with more than one descriptor can cause us
|
||||
// to run out of pool memory early or lead to fragmentation
|
||||
// that makes the pool unable to service our allocation
|
||||
// request. Try the next pool or allocate a new one.
|
||||
continue;
|
||||
case VK_SUCCESS:
|
||||
--pool->free;
|
||||
return pool;
|
||||
default:
|
||||
wlr_vk_error("vkAllocateDescriptorSets", res);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pool = calloc(1, sizeof(*pool));
|
||||
if (!pool) {
|
||||
wlr_log_errno(WLR_ERROR, "allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t count = 2 * (*last_pool_size);
|
||||
if (!count) {
|
||||
count = start_descriptor_pool_size;
|
||||
}
|
||||
|
||||
pool->free = count;
|
||||
VkDescriptorPoolSize pool_size = {
|
||||
.descriptorCount = count,
|
||||
.type = type,
|
||||
};
|
||||
|
||||
VkDescriptorPoolCreateInfo dpool_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.maxSets = count,
|
||||
.poolSizeCount = 1,
|
||||
.pPoolSizes = &pool_size,
|
||||
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
|
||||
};
|
||||
|
||||
res = vkCreateDescriptorPool(renderer->dev->dev, &dpool_info, NULL,
|
||||
&pool->pool);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateDescriptorPool", res);
|
||||
free(pool);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*last_pool_size = count;
|
||||
wl_list_insert(pool_list, &pool->link);
|
||||
|
||||
ds_info.descriptorPool = pool->pool;
|
||||
res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkAllocateDescriptorSets", res);
|
||||
|
|
@ -162,6 +175,8 @@ static void destroy_render_format_setup(struct wlr_vk_renderer *renderer,
|
|||
vkDestroyPipeline(dev, setup->output_pipe_srgb, NULL);
|
||||
vkDestroyPipeline(dev, setup->output_pipe_pq, NULL);
|
||||
vkDestroyPipeline(dev, setup->output_pipe_lut3d, NULL);
|
||||
vkDestroyPipeline(dev, setup->output_pipe_gamma22, NULL);
|
||||
vkDestroyPipeline(dev, setup->output_pipe_bt1886, NULL);
|
||||
|
||||
struct wlr_vk_pipeline *pipeline, *tmp_pipeline;
|
||||
wl_list_for_each_safe(pipeline, tmp_pipeline, &setup->pipelines, link) {
|
||||
|
|
@ -591,6 +606,12 @@ void vulkan_reset_command_buffer(struct wlr_vk_command_buffer *cb) {
|
|||
}
|
||||
}
|
||||
|
||||
static void finish_render_buffer_out(struct wlr_vk_render_buffer_out *out,
|
||||
VkDevice dev) {
|
||||
vkDestroyFramebuffer(dev, out->framebuffer, NULL);
|
||||
vkDestroyImageView(dev, out->image_view, NULL);
|
||||
}
|
||||
|
||||
static void destroy_render_buffer(struct wlr_vk_render_buffer *buffer) {
|
||||
wl_list_remove(&buffer->link);
|
||||
wlr_addon_finish(&buffer->addon);
|
||||
|
|
@ -604,17 +625,16 @@ static void destroy_render_buffer(struct wlr_vk_render_buffer *buffer) {
|
|||
wlr_vk_error("vkQueueWaitIdle", res);
|
||||
}
|
||||
|
||||
vkDestroyFramebuffer(dev, buffer->srgb.framebuffer, NULL);
|
||||
vkDestroyImageView(dev, buffer->srgb.image_view, NULL);
|
||||
finish_render_buffer_out(&buffer->linear.out, dev);
|
||||
finish_render_buffer_out(&buffer->srgb.out, dev);
|
||||
|
||||
vkDestroyFramebuffer(dev, buffer->plain.framebuffer, NULL);
|
||||
vkDestroyImageView(dev, buffer->plain.image_view, NULL);
|
||||
vkDestroyImage(dev, buffer->plain.blend_image, NULL);
|
||||
vkFreeMemory(dev, buffer->plain.blend_memory, NULL);
|
||||
vkDestroyImageView(dev, buffer->plain.blend_image_view, NULL);
|
||||
if (buffer->plain.blend_attachment_pool) {
|
||||
vulkan_free_ds(buffer->renderer, buffer->plain.blend_attachment_pool,
|
||||
buffer->plain.blend_descriptor_set);
|
||||
finish_render_buffer_out(&buffer->two_pass.out, dev);
|
||||
vkDestroyImage(dev, buffer->two_pass.blend_image, NULL);
|
||||
vkFreeMemory(dev, buffer->two_pass.blend_memory, NULL);
|
||||
vkDestroyImageView(dev, buffer->two_pass.blend_image_view, NULL);
|
||||
if (buffer->two_pass.blend_attachment_pool) {
|
||||
vulkan_free_ds(buffer->renderer, buffer->two_pass.blend_attachment_pool,
|
||||
buffer->two_pass.blend_descriptor_set);
|
||||
}
|
||||
|
||||
vkDestroyImage(dev, buffer->image, NULL);
|
||||
|
|
@ -635,7 +655,7 @@ static struct wlr_addon_interface render_buffer_addon_impl = {
|
|||
.destroy = handle_render_buffer_destroy,
|
||||
};
|
||||
|
||||
bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
bool vulkan_setup_two_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
const struct wlr_dmabuf_attributes *dmabuf) {
|
||||
struct wlr_vk_renderer *renderer = buffer->renderer;
|
||||
VkResult res;
|
||||
|
|
@ -663,15 +683,15 @@ bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
},
|
||||
};
|
||||
|
||||
res = vkCreateImageView(dev, &view_info, NULL, &buffer->plain.image_view);
|
||||
res = vkCreateImageView(dev, &view_info, NULL, &buffer->two_pass.out.image_view);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateImageView failed", res);
|
||||
goto error;
|
||||
}
|
||||
|
||||
buffer->plain.render_setup = find_or_create_render_setup(
|
||||
buffer->two_pass.render_setup = find_or_create_render_setup(
|
||||
renderer, &fmt->format, true);
|
||||
if (!buffer->plain.render_setup) {
|
||||
if (!buffer->two_pass.render_setup) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
@ -691,14 +711,14 @@ bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
|
||||
};
|
||||
|
||||
res = vkCreateImage(dev, &img_info, NULL, &buffer->plain.blend_image);
|
||||
res = vkCreateImage(dev, &img_info, NULL, &buffer->two_pass.blend_image);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateImage failed", res);
|
||||
goto error;
|
||||
}
|
||||
|
||||
VkMemoryRequirements mem_reqs;
|
||||
vkGetImageMemoryRequirements(dev, buffer->plain.blend_image, &mem_reqs);
|
||||
vkGetImageMemoryRequirements(dev, buffer->two_pass.blend_image, &mem_reqs);
|
||||
|
||||
int mem_type_index = vulkan_find_mem_type(renderer->dev,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, mem_reqs.memoryTypeBits);
|
||||
|
|
@ -713,13 +733,13 @@ bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
.memoryTypeIndex = mem_type_index,
|
||||
};
|
||||
|
||||
res = vkAllocateMemory(dev, &mem_info, NULL, &buffer->plain.blend_memory);
|
||||
res = vkAllocateMemory(dev, &mem_info, NULL, &buffer->two_pass.blend_memory);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkAllocatorMemory failed", res);
|
||||
goto error;
|
||||
}
|
||||
|
||||
res = vkBindImageMemory(dev, buffer->plain.blend_image, buffer->plain.blend_memory, 0);
|
||||
res = vkBindImageMemory(dev, buffer->two_pass.blend_image, buffer->two_pass.blend_memory, 0);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkBindMemory failed", res);
|
||||
goto error;
|
||||
|
|
@ -727,7 +747,7 @@ bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
|
||||
VkImageViewCreateInfo blend_view_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = buffer->plain.blend_image,
|
||||
.image = buffer->two_pass.blend_image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = img_info.format,
|
||||
.components.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
|
|
@ -743,50 +763,50 @@ bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
},
|
||||
};
|
||||
|
||||
res = vkCreateImageView(dev, &blend_view_info, NULL, &buffer->plain.blend_image_view);
|
||||
res = vkCreateImageView(dev, &blend_view_info, NULL, &buffer->two_pass.blend_image_view);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateImageView failed", res);
|
||||
goto error;
|
||||
}
|
||||
|
||||
buffer->plain.blend_attachment_pool = vulkan_alloc_blend_ds(renderer,
|
||||
&buffer->plain.blend_descriptor_set);
|
||||
if (!buffer->plain.blend_attachment_pool) {
|
||||
buffer->two_pass.blend_attachment_pool = vulkan_alloc_blend_ds(renderer,
|
||||
&buffer->two_pass.blend_descriptor_set);
|
||||
if (!buffer->two_pass.blend_attachment_pool) {
|
||||
wlr_log(WLR_ERROR, "failed to allocate descriptor");
|
||||
goto error;
|
||||
}
|
||||
|
||||
VkDescriptorImageInfo ds_attach_info = {
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
.imageView = buffer->plain.blend_image_view,
|
||||
.imageView = buffer->two_pass.blend_image_view,
|
||||
.sampler = VK_NULL_HANDLE,
|
||||
};
|
||||
VkWriteDescriptorSet ds_write = {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
||||
.dstSet = buffer->plain.blend_descriptor_set,
|
||||
.dstSet = buffer->two_pass.blend_descriptor_set,
|
||||
.dstBinding = 0,
|
||||
.pImageInfo = &ds_attach_info,
|
||||
};
|
||||
vkUpdateDescriptorSets(dev, 1, &ds_write, 0, NULL);
|
||||
|
||||
VkImageView attachments[2] = {
|
||||
buffer->plain.blend_image_view,
|
||||
buffer->plain.image_view
|
||||
VkImageView attachments[] = {
|
||||
buffer->two_pass.blend_image_view,
|
||||
buffer->two_pass.out.image_view,
|
||||
};
|
||||
VkFramebufferCreateInfo fb_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
.attachmentCount = 2,
|
||||
.attachmentCount = sizeof(attachments) / sizeof(attachments[0]),
|
||||
.pAttachments = attachments,
|
||||
.flags = 0u,
|
||||
.width = dmabuf->width,
|
||||
.height = dmabuf->height,
|
||||
.layers = 1u,
|
||||
.renderPass = buffer->plain.render_setup->render_pass,
|
||||
.renderPass = buffer->two_pass.render_setup->render_pass,
|
||||
};
|
||||
|
||||
res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->plain.framebuffer);
|
||||
res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->two_pass.out.framebuffer);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateFramebuffer", res);
|
||||
goto error;
|
||||
|
|
@ -800,8 +820,8 @@ error:
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool vulkan_setup_srgb_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
const struct wlr_dmabuf_attributes *dmabuf) {
|
||||
bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
const struct wlr_dmabuf_attributes *dmabuf, bool srgb) {
|
||||
struct wlr_vk_renderer *renderer = buffer->renderer;
|
||||
VkResult res;
|
||||
VkDevice dev = renderer->dev->dev;
|
||||
|
|
@ -810,14 +830,18 @@ static bool vulkan_setup_srgb_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
renderer->dev, dmabuf->format);
|
||||
assert(fmt);
|
||||
|
||||
assert(fmt->format.vk_srgb);
|
||||
// Set up the srgb framebuffer by default; plain framebuffer and
|
||||
VkFormat vk_fmt = srgb ? fmt->format.vk_srgb : fmt->format.vk;
|
||||
assert(vk_fmt != VK_FORMAT_UNDEFINED);
|
||||
|
||||
struct wlr_vk_render_buffer_out *out = srgb ? &buffer->srgb.out : &buffer->linear.out;
|
||||
|
||||
// Set up the srgb framebuffer by default; two-pass framebuffer and
|
||||
// blending image will be set up later if necessary
|
||||
VkImageViewCreateInfo view_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = buffer->image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = fmt->format.vk_srgb,
|
||||
.format = vk_fmt,
|
||||
.components.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.components.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.components.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
|
|
@ -831,35 +855,43 @@ static bool vulkan_setup_srgb_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
},
|
||||
};
|
||||
|
||||
res = vkCreateImageView(dev, &view_info, NULL, &buffer->srgb.image_view);
|
||||
res = vkCreateImageView(dev, &view_info, NULL, &out->image_view);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateImageView failed", res);
|
||||
goto error;
|
||||
}
|
||||
|
||||
buffer->srgb.render_setup = find_or_create_render_setup(
|
||||
renderer, &fmt->format, false);
|
||||
if (!buffer->srgb.render_setup) {
|
||||
struct wlr_vk_render_format_setup *render_setup =
|
||||
find_or_create_render_setup(renderer, &fmt->format, false);
|
||||
if (!render_setup) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
VkFramebufferCreateInfo fb_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &buffer->srgb.image_view,
|
||||
.pAttachments = &out->image_view,
|
||||
.flags = 0u,
|
||||
.width = dmabuf->width,
|
||||
.height = dmabuf->height,
|
||||
.layers = 1u,
|
||||
.renderPass = buffer->srgb.render_setup->render_pass,
|
||||
.renderPass = render_setup->render_pass,
|
||||
};
|
||||
|
||||
res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->srgb.framebuffer);
|
||||
res = vkCreateFramebuffer(dev, &fb_info, NULL, &out->framebuffer);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateFramebuffer", res);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (srgb) {
|
||||
buffer->srgb.render_setup = render_setup;
|
||||
} else {
|
||||
buffer->linear.render_setup = render_setup;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
// cleaning up everything is the caller's responsibility,
|
||||
// since it will need to do this anyway if framebuffer setup fails
|
||||
|
|
@ -903,12 +935,12 @@ static struct wlr_vk_render_buffer *create_render_buffer(
|
|||
}
|
||||
|
||||
if (using_mutable_srgb) {
|
||||
if (!vulkan_setup_srgb_framebuffer(buffer, &dmabuf)) {
|
||||
if (!vulkan_setup_one_pass_framebuffer(buffer, &dmabuf, true)) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
// Set up the plain framebuffer & blending image
|
||||
if (!vulkan_setup_plain_framebuffer(buffer, &dmabuf)) {
|
||||
// Set up the two-pass framebuffer & blending image
|
||||
if (!vulkan_setup_two_pass_framebuffer(buffer, &dmabuf)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
|
@ -1466,14 +1498,14 @@ static bool init_tex_layouts(struct wlr_vk_renderer *renderer,
|
|||
return false;
|
||||
}
|
||||
|
||||
VkPushConstantRange pc_ranges[2] = {
|
||||
VkPushConstantRange pc_ranges[] = {
|
||||
{
|
||||
.size = sizeof(struct wlr_vk_vert_pcr_data),
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
},
|
||||
{
|
||||
.offset = pc_ranges[0].size,
|
||||
.size = sizeof(float) * 4, // alpha or color
|
||||
.size = sizeof(struct wlr_vk_frag_texture_pcr_data),
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
},
|
||||
};
|
||||
|
|
@ -1482,7 +1514,7 @@ static bool init_tex_layouts(struct wlr_vk_renderer *renderer,
|
|||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = out_ds_layout,
|
||||
.pushConstantRangeCount = 2,
|
||||
.pushConstantRangeCount = sizeof(pc_ranges) / sizeof(pc_ranges[0]),
|
||||
.pPushConstantRanges = pc_ranges,
|
||||
};
|
||||
|
||||
|
|
@ -1560,7 +1592,7 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) {
|
|||
}
|
||||
|
||||
// pipeline layout -- standard vertex uniforms, no shader uniforms
|
||||
VkPushConstantRange pc_ranges[2] = {
|
||||
VkPushConstantRange pc_ranges[] = {
|
||||
{
|
||||
.offset = 0,
|
||||
.size = sizeof(struct wlr_vk_vert_pcr_data),
|
||||
|
|
@ -1573,16 +1605,16 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) {
|
|||
},
|
||||
};
|
||||
|
||||
VkDescriptorSetLayout out_ds_layouts[2] = {
|
||||
VkDescriptorSetLayout out_ds_layouts[] = {
|
||||
renderer->output_ds_srgb_layout,
|
||||
renderer->output_ds_lut3d_layout,
|
||||
};
|
||||
|
||||
VkPipelineLayoutCreateInfo pl_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 2,
|
||||
.setLayoutCount = sizeof(out_ds_layouts) / sizeof(out_ds_layouts[0]),
|
||||
.pSetLayouts = out_ds_layouts,
|
||||
.pushConstantRangeCount = 2,
|
||||
.pushConstantRangeCount = sizeof(pc_ranges) / sizeof(pc_ranges[0]),
|
||||
.pPushConstantRanges = pc_ranges,
|
||||
};
|
||||
|
||||
|
|
@ -1755,14 +1787,14 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline(
|
|||
.scissorCount = 1,
|
||||
};
|
||||
|
||||
VkDynamicState dynStates[2] = {
|
||||
VkDynamicState dyn_states[] = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR,
|
||||
};
|
||||
VkPipelineDynamicStateCreateInfo dynamic = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.pDynamicStates = dynStates,
|
||||
.dynamicStateCount = 2,
|
||||
.pDynamicStates = dyn_states,
|
||||
.dynamicStateCount = sizeof(dyn_states) / sizeof(dyn_states[0]),
|
||||
};
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertex = {
|
||||
|
|
@ -1774,7 +1806,7 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline(
|
|||
.layout = pipeline_layout->vk,
|
||||
.renderPass = setup->render_pass,
|
||||
.subpass = 0,
|
||||
.stageCount = 2,
|
||||
.stageCount = sizeof(stages) / sizeof(stages[0]),
|
||||
.pStages = stages,
|
||||
|
||||
.pInputAssemblyState = &assembly,
|
||||
|
|
@ -1817,7 +1849,7 @@ static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer,
|
|||
.pData = &output_transform_type,
|
||||
};
|
||||
|
||||
VkPipelineShaderStageCreateInfo tex_stages[2] = {
|
||||
VkPipelineShaderStageCreateInfo tex_stages[] = {
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
|
|
@ -1872,14 +1904,14 @@ static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer,
|
|||
.scissorCount = 1,
|
||||
};
|
||||
|
||||
VkDynamicState dynStates[2] = {
|
||||
VkDynamicState dyn_states[] = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR,
|
||||
};
|
||||
VkPipelineDynamicStateCreateInfo dynamic = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.pDynamicStates = dynStates,
|
||||
.dynamicStateCount = 2,
|
||||
.pDynamicStates = dyn_states,
|
||||
.dynamicStateCount = sizeof(dyn_states) / sizeof(dyn_states[0]),
|
||||
};
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertex = {
|
||||
|
|
@ -1892,7 +1924,7 @@ static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer,
|
|||
.layout = pipe_layout,
|
||||
.renderPass = rp,
|
||||
.subpass = 1, // second subpass!
|
||||
.stageCount = 2,
|
||||
.stageCount = sizeof(tex_stages) / sizeof(tex_stages[0]),
|
||||
.pStages = tex_stages,
|
||||
.pInputAssemblyState = &assembly,
|
||||
.pRasterizationState = &rasterization,
|
||||
|
|
@ -2185,7 +2217,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
VkResult res;
|
||||
|
||||
if (use_blending_buffer) {
|
||||
VkAttachmentDescription attachments[2] = {
|
||||
VkAttachmentDescription attachments[] = {
|
||||
{
|
||||
.format = VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
|
|
@ -2223,7 +2255,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
|
||||
VkSubpassDescription subpasses[2] = {
|
||||
VkSubpassDescription subpasses[] = {
|
||||
{
|
||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
.colorAttachmentCount = 1,
|
||||
|
|
@ -2238,7 +2270,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
}
|
||||
};
|
||||
|
||||
VkSubpassDependency deps[3] = {
|
||||
VkSubpassDependency deps[] = {
|
||||
{
|
||||
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_HOST_BIT |
|
||||
|
|
@ -2280,11 +2312,11 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.attachmentCount = 2u,
|
||||
.attachmentCount = sizeof(attachments) / sizeof(attachments[0]),
|
||||
.pAttachments = attachments,
|
||||
.subpassCount = 2u,
|
||||
.subpassCount = sizeof(subpasses) / sizeof(subpasses[0]),
|
||||
.pSubpasses = subpasses,
|
||||
.dependencyCount = 3u,
|
||||
.dependencyCount = sizeof(deps) / sizeof(deps[0]),
|
||||
.pDependencies = deps,
|
||||
};
|
||||
|
||||
|
|
@ -2315,6 +2347,16 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
&setup->output_pipe_pq, WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ)) {
|
||||
goto error;
|
||||
}
|
||||
if (!init_blend_to_output_pipeline(
|
||||
renderer, setup->render_pass, renderer->output_pipe_layout,
|
||||
&setup->output_pipe_gamma22, WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22)) {
|
||||
goto error;
|
||||
}
|
||||
if (!init_blend_to_output_pipeline(
|
||||
renderer, setup->render_pass, renderer->output_pipe_layout,
|
||||
&setup->output_pipe_bt1886, WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886)) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
assert(format->vk_srgb);
|
||||
VkAttachmentDescription attachment = {
|
||||
|
|
@ -2339,7 +2381,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
.pColorAttachments = &color_ref,
|
||||
};
|
||||
|
||||
VkSubpassDependency deps[2] = {
|
||||
VkSubpassDependency deps[] = {
|
||||
{
|
||||
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_HOST_BIT |
|
||||
|
|
@ -2374,7 +2416,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
.pAttachments = &attachment,
|
||||
.subpassCount = 1,
|
||||
.pSubpasses = &subpass,
|
||||
.dependencyCount = 2u,
|
||||
.dependencyCount = sizeof(deps) / sizeof(deps[0]),
|
||||
.pDependencies = deps,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ layout (constant_id = 0) const int OUTPUT_TRANSFORM = 0;
|
|||
#define OUTPUT_TRANSFORM_INVERSE_SRGB 1
|
||||
#define OUTPUT_TRANSFORM_INVERSE_ST2084_PQ 2
|
||||
#define OUTPUT_TRANSFORM_LUT_3D 3
|
||||
#define OUTPUT_TRANSFORM_INVERSE_GAMMA22 4
|
||||
#define OUTPUT_TRANSFORM_INVERSE_BT1886 5
|
||||
|
||||
float linear_channel_to_srgb(float x) {
|
||||
return max(min(x * 12.92, 0.04045), 1.055 * pow(x, 1. / 2.4) - 0.055);
|
||||
|
|
@ -46,6 +48,14 @@ vec3 linear_color_to_pq(vec3 color) {
|
|||
return pow((vec3(c1) + c2 * pow_n) / (vec3(1) + c3 * pow_n), vec3(m));
|
||||
}
|
||||
|
||||
vec3 linear_color_to_bt1886(vec3 color) {
|
||||
float lb = pow(0.0001, 1.0 / 2.4);
|
||||
float lw = pow(1.0, 1.0 / 2.4);
|
||||
float a = pow(lw - lb, 2.4);
|
||||
float b = lb / (lw - lb);
|
||||
return pow(color / a, vec3(1.0 / 2.4)) - vec3(b);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 in_color = subpassLoad(in_color).rgba;
|
||||
|
||||
|
|
@ -71,6 +81,10 @@ void main() {
|
|||
} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_SRGB) {
|
||||
// Produce sRGB encoded values
|
||||
rgb = linear_color_to_srgb(rgb);
|
||||
} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_GAMMA22) {
|
||||
rgb = pow(rgb, vec3(1. / 2.2));
|
||||
} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_BT1886) {
|
||||
rgb = linear_color_to_bt1886(rgb);
|
||||
}
|
||||
|
||||
// Back to pre-multiplied alpha
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ layout (constant_id = 0) const int TEXTURE_TRANSFORM = 0;
|
|||
#define TEXTURE_TRANSFORM_IDENTITY 0
|
||||
#define TEXTURE_TRANSFORM_SRGB 1
|
||||
#define TEXTURE_TRANSFORM_ST2084_PQ 2
|
||||
#define TEXTURE_TRANSFORM_GAMMA22 3
|
||||
#define TEXTURE_TRANSFORM_BT1886 4
|
||||
|
||||
float srgb_channel_to_linear(float x) {
|
||||
return mix(x / 12.92,
|
||||
|
|
@ -44,6 +46,14 @@ vec3 pq_color_to_linear(vec3 color) {
|
|||
return pow(num / denom, vec3(inv_m1));
|
||||
}
|
||||
|
||||
vec3 bt1886_color_to_linear(vec3 color) {
|
||||
float lb = pow(0.0001, 1.0 / 2.4);
|
||||
float lw = pow(1.0, 1.0 / 2.4);
|
||||
float a = pow(lw - lb, 2.4);
|
||||
float b = lb / (lw - lb);
|
||||
return a * pow(color + vec3(b), vec3(2.4));
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 in_color = textureLod(tex, uv, 0);
|
||||
|
||||
|
|
@ -60,6 +70,10 @@ void main() {
|
|||
rgb = srgb_color_to_linear(rgb);
|
||||
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_ST2084_PQ) {
|
||||
rgb = pq_color_to_linear(rgb);
|
||||
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_GAMMA22) {
|
||||
rgb = pow(rgb, vec3(2.2));
|
||||
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_BT1886) {
|
||||
rgb = bt1886_color_to_linear(rgb);
|
||||
}
|
||||
|
||||
rgb *= data.luminance_multiplier;
|
||||
|
|
|
|||
|
|
@ -399,14 +399,14 @@ static struct wlr_texture *vulkan_texture_from_pixels(
|
|||
|
||||
texture_set_format(texture, &fmt->format, fmt->shm.has_mutable_srgb);
|
||||
|
||||
VkFormat view_formats[2] = {
|
||||
VkFormat view_formats[] = {
|
||||
fmt->format.vk,
|
||||
fmt->format.vk_srgb,
|
||||
};
|
||||
VkImageFormatListCreateInfoKHR list_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
|
||||
.pViewFormats = view_formats,
|
||||
.viewFormatCount = 2,
|
||||
.viewFormatCount = sizeof(view_formats) / sizeof(view_formats[0]),
|
||||
};
|
||||
VkImageCreateInfo img_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
|
|
@ -600,14 +600,14 @@ VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer,
|
|||
};
|
||||
eimg.pNext = &mod_info;
|
||||
|
||||
VkFormat view_formats[2] = {
|
||||
VkFormat view_formats[] = {
|
||||
fmt->format.vk,
|
||||
fmt->format.vk_srgb,
|
||||
};
|
||||
VkImageFormatListCreateInfoKHR list_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
|
||||
.pViewFormats = view_formats,
|
||||
.viewFormatCount = 2,
|
||||
.viewFormatCount = sizeof(view_formats) / sizeof(view_formats[0]),
|
||||
};
|
||||
if (mod->has_mutable_srgb) {
|
||||
mod_info.pNext = &list_info;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
PKG_CONFIG?=pkg-config
|
||||
WAYLAND_PROTOCOLS!=$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols
|
||||
WAYLAND_SCANNER!=$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner
|
||||
|
||||
PKGS="wlroots-0.20" wayland-server xkbcommon
|
||||
CFLAGS_PKG_CONFIG!=$(PKG_CONFIG) --cflags $(PKGS)
|
||||
|
|
@ -9,19 +7,12 @@ LIBS!=$(PKG_CONFIG) --libs $(PKGS)
|
|||
|
||||
all: tinywl
|
||||
|
||||
# wayland-scanner is a tool which generates C headers and rigging for Wayland
|
||||
# protocols, which are specified in XML. wlroots requires you to rig these up
|
||||
# to your build system yourself and provide them in the include path.
|
||||
xdg-shell-protocol.h:
|
||||
$(WAYLAND_SCANNER) server-header \
|
||||
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
|
||||
|
||||
tinywl.o: tinywl.c xdg-shell-protocol.h
|
||||
tinywl.o: tinywl.c
|
||||
$(CC) -c $< -g -Werror $(CFLAGS) -I. -DWLR_USE_UNSTABLE -o $@
|
||||
tinywl: tinywl.o
|
||||
$(CC) $^ $> -g -Werror $(CFLAGS) $(LDFLAGS) $(LIBS) -o $@
|
||||
|
||||
clean:
|
||||
rm -f tinywl tinywl.o xdg-shell-protocol.h
|
||||
rm -f tinywl tinywl.o
|
||||
|
||||
.PHONY: all clean
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
executable(
|
||||
'tinywl',
|
||||
['tinywl.c', protocols_server_header['xdg-shell']],
|
||||
'tinywl.c',
|
||||
dependencies: wlroots,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ struct tinywl_server {
|
|||
struct wlr_seat *seat;
|
||||
struct wl_listener new_input;
|
||||
struct wl_listener request_cursor;
|
||||
struct wl_listener pointer_focus_change;
|
||||
struct wl_listener request_set_selection;
|
||||
struct wl_list keyboards;
|
||||
enum tinywl_cursor_mode cursor_mode;
|
||||
|
|
@ -333,6 +334,18 @@ static void seat_request_cursor(struct wl_listener *listener, void *data) {
|
|||
}
|
||||
}
|
||||
|
||||
static void seat_pointer_focus_change(struct wl_listener *listener, void *data) {
|
||||
struct tinywl_server *server = wl_container_of(
|
||||
listener, server, pointer_focus_change);
|
||||
/* This event is raised when the pointer focus is changed, including when the
|
||||
* client is closed. We set the cursor image to its default if target surface
|
||||
* is NULL */
|
||||
struct wlr_seat_pointer_focus_change_event *event = data;
|
||||
if (event->new_surface == NULL) {
|
||||
wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "default");
|
||||
}
|
||||
}
|
||||
|
||||
static void seat_request_set_selection(struct wl_listener *listener, void *data) {
|
||||
/* This event is raised by the seat when a client wants to set the selection,
|
||||
* usually when the user copies something. wlroots allows compositors to
|
||||
|
|
@ -1018,6 +1031,9 @@ int main(int argc, char *argv[]) {
|
|||
server.request_cursor.notify = seat_request_cursor;
|
||||
wl_signal_add(&server.seat->events.request_set_cursor,
|
||||
&server.request_cursor);
|
||||
server.pointer_focus_change.notify = seat_pointer_focus_change;
|
||||
wl_signal_add(&server.seat->pointer_state.events.focus_change,
|
||||
&server.pointer_focus_change);
|
||||
server.request_set_selection.notify = seat_request_set_selection;
|
||||
wl_signal_add(&server.seat->events.request_set_selection,
|
||||
&server.request_set_selection);
|
||||
|
|
@ -1069,6 +1085,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
wl_list_remove(&server.new_input.link);
|
||||
wl_list_remove(&server.request_cursor.link);
|
||||
wl_list_remove(&server.pointer_focus_change.link);
|
||||
wl_list_remove(&server.request_set_selection.link);
|
||||
|
||||
wl_list_remove(&server.new_output.link);
|
||||
|
|
|
|||
|
|
@ -308,6 +308,14 @@ static void drag_handle_touch_motion(struct wlr_seat_touch_grab *grab,
|
|||
wl_fixed_from_double(point->sx),
|
||||
wl_fixed_from_double(point->sy));
|
||||
}
|
||||
|
||||
struct wlr_drag_motion_event event = {
|
||||
.drag = drag,
|
||||
.time = time,
|
||||
.sx = point->sx,
|
||||
.sy = point->sy,
|
||||
};
|
||||
wl_signal_emit_mutable(&drag->events.motion, &event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <wlr/types/wlr_ext_image_capture_source_v1.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "ext-image-capture-source-v1-protocol.h"
|
||||
#include "render/wlr_renderer.h"
|
||||
|
||||
static void source_handle_destroy(struct wl_client *client,
|
||||
struct wl_resource *source_resource) {
|
||||
|
|
@ -96,6 +97,12 @@ static uint32_t get_swapchain_shm_format(struct wlr_swapchain *swapchain,
|
|||
return format;
|
||||
}
|
||||
|
||||
static void add_drm_format(struct wlr_drm_format_set *set, const struct wlr_drm_format *fmt) {
|
||||
for (size_t i = 0; i < fmt->len; i++) {
|
||||
wlr_drm_format_set_add(set, fmt->format, fmt->modifiers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool wlr_ext_image_capture_source_v1_set_constraints_from_swapchain(struct wlr_ext_image_capture_source_v1 *source,
|
||||
struct wlr_swapchain *swapchain, struct wlr_renderer *renderer) {
|
||||
source->width = swapchain->width;
|
||||
|
|
@ -130,9 +137,21 @@ bool wlr_ext_image_capture_source_v1_set_constraints_from_swapchain(struct wlr_e
|
|||
wlr_drm_format_set_finish(&source->dmabuf_formats);
|
||||
source->dmabuf_formats = (struct wlr_drm_format_set){0};
|
||||
|
||||
for (size_t i = 0; i < swapchain->format.len; i++) {
|
||||
wlr_drm_format_set_add(&source->dmabuf_formats,
|
||||
swapchain->format.format, swapchain->format.modifiers[i]);
|
||||
add_drm_format(&source->dmabuf_formats, &swapchain->format);
|
||||
|
||||
const struct wlr_drm_format_set *render_formats =
|
||||
wlr_renderer_get_render_formats(renderer);
|
||||
assert(render_formats != NULL);
|
||||
|
||||
// Not all clients support fancy formats. Always ensure we provide
|
||||
// support for ARGB8888 and XRGB8888 for simple clients.
|
||||
uint32_t fallback_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888 };
|
||||
for (size_t i = 0; i < sizeof(fallback_formats) / sizeof(fallback_formats[0]); i++) {
|
||||
const struct wlr_drm_format *fmt =
|
||||
wlr_drm_format_set_get(render_formats, fallback_formats[i]);
|
||||
if (fmt != NULL && swapchain->format.format != fmt->format) {
|
||||
add_drm_format(&source->dmabuf_formats, fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,6 @@
|
|||
|
||||
#define FOREIGN_TOPLEVEL_IMAGE_SOURCE_MANAGER_V1_VERSION 1
|
||||
|
||||
struct wlr_ext_foreign_toplevel_image_capture_source_v1 {
|
||||
struct wlr_ext_image_capture_source_v1 base;
|
||||
};
|
||||
|
||||
static const struct ext_foreign_toplevel_image_capture_source_manager_v1_interface foreign_toplevel_manager_impl;
|
||||
|
||||
static struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *
|
||||
|
|
|
|||
|
|
@ -283,7 +283,8 @@ static void output_cursor_source_copy_frame(struct wlr_ext_image_capture_source_
|
|||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
wlr_ext_image_copy_capture_frame_v1_ready(frame, WL_OUTPUT_TRANSFORM_NORMAL, &now);
|
||||
wlr_ext_image_copy_capture_frame_v1_ready(frame,
|
||||
cursor_source->output->transform, &now);
|
||||
}
|
||||
|
||||
static const struct wlr_ext_image_capture_source_v1_interface output_cursor_source_impl = {
|
||||
|
|
|
|||
|
|
@ -39,19 +39,20 @@ wlr_files += files(
|
|||
'buffer/resource.c',
|
||||
'wlr_alpha_modifier_v1.c',
|
||||
'wlr_color_management_v1.c',
|
||||
'wlr_color_representation_v1.c',
|
||||
'wlr_compositor.c',
|
||||
'wlr_content_type_v1.c',
|
||||
'wlr_cursor_shape_v1.c',
|
||||
'wlr_cursor.c',
|
||||
'wlr_cursor_shape_v1.c',
|
||||
'wlr_damage_ring.c',
|
||||
'wlr_data_control_v1.c',
|
||||
'wlr_drm.c',
|
||||
'wlr_export_dmabuf_v1.c',
|
||||
'wlr_foreign_toplevel_management_v1.c',
|
||||
'wlr_color_representation_v1.c',
|
||||
'wlr_ext_image_copy_capture_v1.c',
|
||||
'wlr_ext_foreign_toplevel_list_v1.c',
|
||||
'wlr_ext_data_control_v1.c',
|
||||
'wlr_ext_foreign_toplevel_list_v1.c',
|
||||
'wlr_ext_image_copy_capture_v1.c',
|
||||
'wlr_fixes.c',
|
||||
'wlr_foreign_toplevel_management_v1.c',
|
||||
'wlr_fractional_scale_v1.c',
|
||||
'wlr_gamma_control_v1.c',
|
||||
'wlr_idle_inhibit_v1.c',
|
||||
|
|
|
|||
|
|
@ -288,18 +288,10 @@ static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor)
|
|||
static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) {
|
||||
struct wlr_output *output = cursor->output;
|
||||
|
||||
if (!output->impl->set_cursor ||
|
||||
output->software_cursor_locks > 0) {
|
||||
if (!output->impl->set_cursor || output->software_cursor_locks > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct wlr_output_cursor *hwcur = output->hardware_cursor;
|
||||
if (hwcur != NULL && hwcur != cursor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
output->hardware_cursor = NULL;
|
||||
|
||||
struct wlr_texture *texture = cursor->texture;
|
||||
|
||||
// If the cursor was hidden or was a software cursor, the hardware
|
||||
|
|
@ -424,12 +416,15 @@ bool output_cursor_set_texture(struct wlr_output_cursor *cursor,
|
|||
wl_list_init(&cursor->renderer_destroy.link);
|
||||
}
|
||||
|
||||
if (output_cursor_attempt_hardware(cursor)) {
|
||||
return true;
|
||||
if (output->hardware_cursor == NULL || output->hardware_cursor == cursor) {
|
||||
if (output_cursor_attempt_hardware(cursor)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
wlr_log(WLR_DEBUG, "Falling back to software cursor on output '%s'", output->name);
|
||||
output_disable_hardware_cursor(output);
|
||||
}
|
||||
|
||||
wlr_log(WLR_DEBUG, "Falling back to software cursor on output '%s'", output->name);
|
||||
output_disable_hardware_cursor(output);
|
||||
output_cursor_damage_whole(cursor);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,6 +242,15 @@ static void output_apply_state(struct wlr_output *output,
|
|||
}
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
wlr_color_transform_unref(output->color_transform);
|
||||
if (state->color_transform != NULL) {
|
||||
output->color_transform = wlr_color_transform_ref(state->color_transform);
|
||||
} else {
|
||||
output->color_transform = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool geometry_updated = state->committed &
|
||||
(WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM |
|
||||
WLR_OUTPUT_STATE_SUBPIXEL);
|
||||
|
|
@ -407,6 +416,7 @@ void wlr_output_finish(struct wlr_output *output) {
|
|||
|
||||
wlr_swapchain_destroy(output->cursor_swapchain);
|
||||
wlr_buffer_unlock(output->cursor_front_buffer);
|
||||
wlr_color_transform_unref(output->color_transform);
|
||||
|
||||
wlr_swapchain_destroy(output->swapchain);
|
||||
|
||||
|
|
@ -515,8 +525,7 @@ const struct wlr_output_image_description *output_pending_image_description(
|
|||
* Returns a bitfield of the unchanged fields.
|
||||
*
|
||||
* Some fields are not checked: damage always changes in-between frames, the
|
||||
* gamma LUT is too expensive to check, the contents of the buffer might have
|
||||
* changed, etc.
|
||||
* contents of the buffer might have changed, etc.
|
||||
*/
|
||||
static uint32_t output_compare_state(struct wlr_output *output,
|
||||
const struct wlr_output_state *state) {
|
||||
|
|
@ -562,6 +571,10 @@ static uint32_t output_compare_state(struct wlr_output *output,
|
|||
output->subpixel == state->subpixel) {
|
||||
fields |= WLR_OUTPUT_STATE_SUBPIXEL;
|
||||
}
|
||||
if ((state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) &&
|
||||
output->color_transform == state->color_transform) {
|
||||
fields |= WLR_OUTPUT_STATE_COLOR_TRANSFORM;
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
|
@ -759,7 +772,9 @@ void output_apply_commit(struct wlr_output *output, const struct wlr_output_stat
|
|||
}
|
||||
|
||||
output_apply_state(output, state);
|
||||
}
|
||||
|
||||
void output_send_commit_event(struct wlr_output *output, const struct wlr_output_state *state) {
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
struct wlr_output_event_commit event = {
|
||||
|
|
@ -801,6 +816,7 @@ bool wlr_output_commit_state(struct wlr_output *output,
|
|||
}
|
||||
|
||||
output_apply_commit(output, &pending);
|
||||
output_send_commit_event(output, &pending);
|
||||
|
||||
if (new_back_buffer) {
|
||||
wlr_buffer_unlock(pending.buffer);
|
||||
|
|
|
|||
|
|
@ -35,16 +35,76 @@ static struct wlr_output *get_surface_frame_pacing_output(struct wlr_surface *su
|
|||
return frame_pacing_output;
|
||||
}
|
||||
|
||||
static bool get_tf_preference(enum wlr_color_transfer_function tf) {
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||
return 0;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
return 1;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
return -1;
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
static bool get_primaries_preference(enum wlr_color_named_primaries primaries) {
|
||||
switch (primaries) {
|
||||
case WLR_COLOR_NAMED_PRIMARIES_SRGB:
|
||||
return 0;
|
||||
case WLR_COLOR_NAMED_PRIMARIES_BT2020:
|
||||
return 1;
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
static void get_surface_preferred_image_description(struct wlr_surface *surface,
|
||||
struct wlr_image_description_v1_data *out) {
|
||||
struct wlr_output_image_description preferred = {
|
||||
.transfer_function = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22,
|
||||
.primaries = WLR_COLOR_NAMED_PRIMARIES_SRGB,
|
||||
};
|
||||
|
||||
struct wlr_surface_output *surface_output;
|
||||
wl_list_for_each(surface_output, &surface->current_outputs, link) {
|
||||
const struct wlr_output_image_description *img_desc =
|
||||
surface_output->output->image_description;
|
||||
if (img_desc == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (get_tf_preference(preferred.transfer_function) < get_tf_preference(img_desc->transfer_function)) {
|
||||
preferred.transfer_function = img_desc->transfer_function;
|
||||
}
|
||||
if (get_primaries_preference(preferred.primaries) < get_primaries_preference(img_desc->primaries)) {
|
||||
preferred.primaries = img_desc->primaries;
|
||||
}
|
||||
}
|
||||
|
||||
*out = (struct wlr_image_description_v1_data){
|
||||
.tf_named = wlr_color_manager_v1_transfer_function_from_wlr(preferred.transfer_function),
|
||||
.primaries_named = wlr_color_manager_v1_primaries_from_wlr(preferred.primaries),
|
||||
};
|
||||
}
|
||||
|
||||
static void handle_scene_buffer_outputs_update(
|
||||
struct wl_listener *listener, void *data) {
|
||||
struct wlr_scene_surface *surface =
|
||||
wl_container_of(listener, surface, outputs_update);
|
||||
struct wlr_scene *scene = scene_node_get_root(&surface->buffer->node);
|
||||
|
||||
surface->frame_pacing_output = get_surface_frame_pacing_output(surface->surface);
|
||||
|
||||
double scale = get_surface_preferred_buffer_scale(surface->surface);
|
||||
wlr_fractional_scale_v1_notify_scale(surface->surface, scale);
|
||||
wlr_surface_set_preferred_buffer_scale(surface->surface, ceil(scale));
|
||||
|
||||
if (scene->color_manager_v1 != NULL) {
|
||||
struct wlr_image_description_v1_data img_desc = {0};
|
||||
get_surface_preferred_image_description(surface->surface, &img_desc);
|
||||
wlr_color_manager_v1_set_surface_preferred_image_description(scene->color_manager_v1,
|
||||
surface->surface, &img_desc);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_scene_buffer_output_enter(
|
||||
|
|
@ -190,35 +250,13 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
|
|||
opacity = (float)alpha_modifier_state->multiplier;
|
||||
}
|
||||
|
||||
enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_SRGB;
|
||||
enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
enum wlr_color_named_primaries primaries = WLR_COLOR_NAMED_PRIMARIES_SRGB;
|
||||
const struct wlr_image_description_v1_data *img_desc =
|
||||
wlr_surface_get_image_description_v1_data(surface);
|
||||
if (img_desc != NULL) {
|
||||
switch (img_desc->tf_named) {
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB:
|
||||
tf = WLR_COLOR_TRANSFER_FUNCTION_SRGB;
|
||||
break;
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
tf = WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
|
||||
break;
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
tf = WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
switch (img_desc->primaries_named) {
|
||||
case WP_COLOR_MANAGER_V1_PRIMARIES_SRGB:
|
||||
primaries = WLR_COLOR_NAMED_PRIMARIES_SRGB;
|
||||
break;
|
||||
case WP_COLOR_MANAGER_V1_PRIMARIES_BT2020:
|
||||
primaries = WLR_COLOR_NAMED_PRIMARIES_BT2020;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
tf = wlr_color_manager_v1_transfer_function_to_wlr(img_desc->tf_named);
|
||||
primaries = wlr_color_manager_v1_primaries_to_wlr(img_desc->primaries_named);
|
||||
}
|
||||
|
||||
wlr_scene_buffer_set_opaque_region(scene_buffer, &opaque);
|
||||
|
|
@ -239,10 +277,9 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
|
|||
// can't use the cached scene_buffer->is_single_pixel_buffer
|
||||
// because that's only set later on.
|
||||
bool is_single_pixel_buffer = false;
|
||||
struct wlr_client_buffer *client_buffer = wlr_client_buffer_get(&surface->buffer->base);
|
||||
if (client_buffer != NULL && client_buffer->source != NULL) {
|
||||
if (surface->buffer->source != NULL) {
|
||||
struct wlr_single_pixel_buffer_v1 *spb =
|
||||
wlr_single_pixel_buffer_v1_try_from_buffer(client_buffer->source);
|
||||
wlr_single_pixel_buffer_v1_try_from_buffer(surface->buffer->source);
|
||||
is_single_pixel_buffer = spb != NULL;
|
||||
}
|
||||
if (!is_single_pixel_buffer) {
|
||||
|
|
@ -268,7 +305,8 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
|
|||
&surface->buffer->base, &options);
|
||||
|
||||
if (syncobj_surface_state != NULL &&
|
||||
(surface->current.committed & WLR_SURFACE_STATE_BUFFER)) {
|
||||
(surface->current.committed & WLR_SURFACE_STATE_BUFFER) &&
|
||||
surface->buffer->source != NULL) {
|
||||
wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(syncobj_surface_state,
|
||||
surface->buffer->source);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <wlr/render/swapchain.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_color_management_v1.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_damage_ring.h>
|
||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||
|
|
@ -1529,6 +1530,8 @@ static void scene_handle_gamma_control_manager_v1_set_gamma(struct wl_listener *
|
|||
|
||||
output->gamma_lut_changed = true;
|
||||
output->gamma_lut = event->control;
|
||||
wlr_color_transform_unref(output->gamma_lut_color_transform);
|
||||
output->gamma_lut_color_transform = wlr_gamma_control_v1_get_color_transform(event->control);
|
||||
wlr_output_schedule_frame(output->output);
|
||||
}
|
||||
|
||||
|
|
@ -1546,6 +1549,8 @@ static void scene_handle_gamma_control_manager_v1_destroy(struct wl_listener *li
|
|||
wl_list_for_each(output, &scene->outputs, link) {
|
||||
output->gamma_lut_changed = false;
|
||||
output->gamma_lut = NULL;
|
||||
wlr_color_transform_unref(output->gamma_lut_color_transform);
|
||||
output->gamma_lut_color_transform = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1562,6 +1567,21 @@ void wlr_scene_set_gamma_control_manager_v1(struct wlr_scene *scene,
|
|||
wl_signal_add(&gamma_control->events.set_gamma, &scene->gamma_control_manager_v1_set_gamma);
|
||||
}
|
||||
|
||||
static void scene_handle_color_manager_v1_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_scene *scene = wl_container_of(listener, scene, color_manager_v1_destroy);
|
||||
wl_list_remove(&scene->color_manager_v1_destroy.link);
|
||||
wl_list_init(&scene->color_manager_v1_destroy.link);
|
||||
scene->color_manager_v1 = NULL;
|
||||
}
|
||||
|
||||
void wlr_scene_set_color_manager_v1(struct wlr_scene *scene, struct wlr_color_manager_v1 *manager) {
|
||||
assert(scene->color_manager_v1 == NULL);
|
||||
scene->color_manager_v1 = manager;
|
||||
|
||||
scene->color_manager_v1_destroy.notify = scene_handle_color_manager_v1_destroy;
|
||||
wl_signal_add(&manager->events.destroy, &scene->color_manager_v1_destroy);
|
||||
}
|
||||
|
||||
static void scene_output_handle_destroy(struct wlr_addon *addon) {
|
||||
struct wlr_scene_output *scene_output =
|
||||
wl_container_of(addon, scene_output, addon);
|
||||
|
|
@ -1750,6 +1770,10 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) {
|
|||
wl_list_remove(&scene_output->output_damage.link);
|
||||
wl_list_remove(&scene_output->output_needs_frame.link);
|
||||
wlr_drm_syncobj_timeline_unref(scene_output->in_timeline);
|
||||
wlr_color_transform_unref(scene_output->gamma_lut_color_transform);
|
||||
wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform);
|
||||
wlr_color_transform_unref(scene_output->prev_supplied_color_transform);
|
||||
wlr_color_transform_unref(scene_output->prev_combined_color_transform);
|
||||
wl_array_release(&scene_output->render_list);
|
||||
free(scene_output);
|
||||
}
|
||||
|
|
@ -1909,6 +1933,27 @@ static void scene_buffer_send_dmabuf_feedback(const struct wlr_scene *scene,
|
|||
wlr_linux_dmabuf_feedback_v1_finish(&feedback);
|
||||
}
|
||||
|
||||
static bool color_management_is_scanout_allowed(const struct wlr_output_image_description *img_desc,
|
||||
const struct wlr_scene_buffer *buffer) {
|
||||
// Disallow scanout if the output has colorimetry information but buffer
|
||||
// doesn't; allow it only if the output also lacks it.
|
||||
if (buffer->transfer_function == 0 && buffer->primaries == 0) {
|
||||
return img_desc == NULL;
|
||||
}
|
||||
|
||||
// If the output has colorimetry information, the buffer must match it for
|
||||
// direct scanout to be allowed.
|
||||
if (img_desc != NULL) {
|
||||
return img_desc->transfer_function == buffer->transfer_function &&
|
||||
img_desc->primaries == buffer->primaries;
|
||||
}
|
||||
// If the output doesn't have colorimetry image description set, we can only
|
||||
// scan out buffers with default colorimetry (gamma2.2 transfer and sRGB
|
||||
// primaries) used in wlroots.
|
||||
return buffer->transfer_function == WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 &&
|
||||
buffer->primaries == WLR_COLOR_NAMED_PRIMARIES_SRGB;
|
||||
}
|
||||
|
||||
enum scene_direct_scanout_result {
|
||||
// This scene node is not a candidate for scanout
|
||||
SCANOUT_INELIGIBLE,
|
||||
|
|
@ -1966,20 +2011,8 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout(
|
|||
}
|
||||
|
||||
const struct wlr_output_image_description *img_desc = output_pending_image_description(scene_output->output, state);
|
||||
if (buffer->transfer_function != 0 || buffer->primaries != 0) {
|
||||
if (img_desc == NULL || img_desc->transfer_function != buffer->transfer_function ||
|
||||
img_desc->primaries != buffer->primaries) {
|
||||
return false;
|
||||
}
|
||||
} else if (img_desc != NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer->transfer_function != 0 && buffer->transfer_function != WLR_COLOR_TRANSFER_FUNCTION_SRGB) {
|
||||
return false;
|
||||
}
|
||||
if (buffer->primaries != 0 && buffer->primaries != WLR_COLOR_NAMED_PRIMARIES_SRGB) {
|
||||
return false;
|
||||
if (!color_management_is_scanout_allowed(img_desc, buffer)) {
|
||||
return SCANOUT_INELIGIBLE;
|
||||
}
|
||||
|
||||
// We want to ensure optimal buffer selection, but as direct-scanout can be enabled and disabled
|
||||
|
|
@ -2079,16 +2112,15 @@ static void scene_output_state_attempt_gamma(struct wlr_scene_output *scene_outp
|
|||
return;
|
||||
}
|
||||
|
||||
if (!wlr_gamma_control_v1_apply(scene_output->gamma_lut, &gamma_pending)) {
|
||||
wlr_output_state_finish(&gamma_pending);
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_output_state_set_color_transform(&gamma_pending, scene_output->gamma_lut_color_transform);
|
||||
scene_output->gamma_lut_changed = false;
|
||||
|
||||
if (!wlr_output_test_state(scene_output->output, &gamma_pending)) {
|
||||
wlr_gamma_control_v1_send_failed_and_destroy(scene_output->gamma_lut);
|
||||
|
||||
scene_output->gamma_lut = NULL;
|
||||
wlr_color_transform_unref(scene_output->gamma_lut_color_transform);
|
||||
scene_output->gamma_lut_color_transform = NULL;
|
||||
wlr_output_state_finish(&gamma_pending);
|
||||
return;
|
||||
}
|
||||
|
|
@ -2097,6 +2129,41 @@ static void scene_output_state_attempt_gamma(struct wlr_scene_output *scene_outp
|
|||
wlr_output_state_finish(&gamma_pending);
|
||||
}
|
||||
|
||||
static struct wlr_color_transform *scene_output_combine_color_transforms(
|
||||
struct wlr_scene_output *scene_output, struct wlr_color_transform *supplied) {
|
||||
struct wlr_color_transform *gamma_lut = scene_output->gamma_lut_color_transform;
|
||||
assert(gamma_lut != NULL);
|
||||
|
||||
if (gamma_lut == scene_output->prev_gamma_lut_color_transform &&
|
||||
supplied == scene_output->prev_supplied_color_transform) {
|
||||
return wlr_color_transform_ref(scene_output->prev_combined_color_transform);
|
||||
}
|
||||
|
||||
struct wlr_color_transform *combined;
|
||||
if (supplied == NULL) {
|
||||
combined = wlr_color_transform_ref(gamma_lut);
|
||||
} else {
|
||||
struct wlr_color_transform *transforms[] = {
|
||||
gamma_lut,
|
||||
supplied,
|
||||
};
|
||||
size_t transforms_len = sizeof(transforms) / sizeof(transforms[0]);
|
||||
combined = wlr_color_transform_init_pipeline(transforms, transforms_len);
|
||||
if (combined == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform);
|
||||
scene_output->prev_gamma_lut_color_transform = wlr_color_transform_ref(gamma_lut);
|
||||
wlr_color_transform_unref(scene_output->prev_supplied_color_transform);
|
||||
scene_output->prev_supplied_color_transform = supplied ? wlr_color_transform_ref(supplied) : NULL;
|
||||
wlr_color_transform_unref(scene_output->prev_combined_color_transform);
|
||||
scene_output->prev_combined_color_transform = wlr_color_transform_ref(combined);
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
||||
bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||
struct wlr_output_state *state, const struct wlr_scene_output_state_options *options) {
|
||||
struct wlr_scene_output_state_options default_options = {0};
|
||||
|
|
@ -2120,6 +2187,16 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
enum wlr_scene_debug_damage_option debug_damage =
|
||||
scene_output->scene->debug_damage_option;
|
||||
|
||||
bool render_gamma_lut = false;
|
||||
if (wlr_output_get_gamma_size(output) == 0 && output->renderer->features.output_color_transform) {
|
||||
if (scene_output->gamma_lut_color_transform != scene_output->prev_gamma_lut_color_transform) {
|
||||
scene_output_damage_whole(scene_output);
|
||||
}
|
||||
if (scene_output->gamma_lut_color_transform != NULL) {
|
||||
render_gamma_lut = true;
|
||||
}
|
||||
}
|
||||
|
||||
struct render_data render_data = {
|
||||
.transform = output->transform,
|
||||
.scale = output->scale,
|
||||
|
|
@ -2220,7 +2297,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
// - There are no color transforms that need to be applied
|
||||
// - Damage highlight debugging is not enabled
|
||||
enum scene_direct_scanout_result scanout_result = SCANOUT_INELIGIBLE;
|
||||
if (options->color_transform == NULL && list_len == 1
|
||||
if (options->color_transform == NULL && !render_gamma_lut && list_len == 1
|
||||
&& debug_damage != WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
|
||||
scanout_result = scene_entry_try_direct_scanout(&list_data[0], state, &render_data);
|
||||
}
|
||||
|
|
@ -2294,6 +2371,17 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
color_transform = wlr_color_transform_ref(options->color_transform);
|
||||
}
|
||||
|
||||
if (render_gamma_lut) {
|
||||
struct wlr_color_transform *combined =
|
||||
scene_output_combine_color_transforms(scene_output, color_transform);
|
||||
wlr_color_transform_unref(color_transform);
|
||||
if (combined == NULL) {
|
||||
wlr_buffer_unlock(buffer);
|
||||
return false;
|
||||
}
|
||||
color_transform = combined;
|
||||
}
|
||||
|
||||
scene_output->in_point++;
|
||||
struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(output->renderer, buffer,
|
||||
&(struct wlr_buffer_pass_options){
|
||||
|
|
@ -2416,7 +2504,9 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
scene_output->in_point);
|
||||
}
|
||||
|
||||
scene_output_state_attempt_gamma(scene_output, state);
|
||||
if (!render_gamma_lut) {
|
||||
scene_output_state_attempt_gamma(scene_output, state);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/util/addon.h>
|
||||
|
||||
#include "color-management-v1-protocol.h"
|
||||
#include "render/color.h"
|
||||
#include "util/mem.h"
|
||||
|
||||
|
|
@ -64,32 +65,6 @@ static void resource_handle_destroy(struct wl_client *client, struct wl_resource
|
|||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static enum wlr_color_named_primaries named_primaries_to_wlr(
|
||||
enum wp_color_manager_v1_primaries primaries) {
|
||||
switch (primaries) {
|
||||
case WP_COLOR_MANAGER_V1_PRIMARIES_SRGB:
|
||||
return WLR_COLOR_NAMED_PRIMARIES_SRGB;
|
||||
case WP_COLOR_MANAGER_V1_PRIMARIES_BT2020:
|
||||
return WLR_COLOR_NAMED_PRIMARIES_BT2020;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static enum wlr_color_transfer_function transfer_function_to_wlr(
|
||||
enum wp_color_manager_v1_transfer_function tf) {
|
||||
switch (tf) {
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB:
|
||||
return WLR_COLOR_TRANSFER_FUNCTION_SRGB;
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
return WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
return WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t encode_cie1931_coord(float value) {
|
||||
return round(value * 1000 * 1000);
|
||||
}
|
||||
|
|
@ -131,10 +106,12 @@ static void image_desc_handle_get_information(struct wl_client *client,
|
|||
}
|
||||
|
||||
struct wlr_color_primaries primaries;
|
||||
wlr_color_primaries_from_named(&primaries, named_primaries_to_wlr(image_desc->data.primaries_named));
|
||||
wlr_color_primaries_from_named(&primaries,
|
||||
wlr_color_manager_v1_primaries_to_wlr(image_desc->data.primaries_named));
|
||||
|
||||
struct wlr_color_luminances luminances;
|
||||
wlr_color_transfer_function_get_default_luminance(transfer_function_to_wlr(image_desc->data.tf_named), &luminances);
|
||||
wlr_color_transfer_function_get_default_luminance(
|
||||
wlr_color_manager_v1_transfer_function_to_wlr(image_desc->data.tf_named), &luminances);
|
||||
|
||||
wp_image_description_info_v1_send_primaries_named(resource, image_desc->data.primaries_named);
|
||||
wp_image_description_info_v1_send_primaries(resource,
|
||||
|
|
@ -235,9 +212,14 @@ static void cm_output_handle_get_image_description(struct wl_client *client,
|
|||
}
|
||||
|
||||
struct wlr_image_description_v1_data data = {
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
|
||||
.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
|
||||
};
|
||||
const struct wlr_output_image_description *image_desc = cm_output->output->image_description;
|
||||
if (image_desc != NULL) {
|
||||
data.tf_named = wlr_color_manager_v1_transfer_function_from_wlr(image_desc->transfer_function);
|
||||
data.primaries_named = wlr_color_manager_v1_primaries_from_wlr(image_desc->primaries);
|
||||
}
|
||||
image_desc_create_ready(cm_output->manager, cm_output_resource, id, &data, true);
|
||||
}
|
||||
|
||||
|
|
@ -310,6 +292,13 @@ static void cm_surface_handle_set_image_description(struct wl_client *client,
|
|||
|
||||
struct wlr_image_description_v1 *image_desc = image_desc_from_resource(image_desc_resource);
|
||||
|
||||
if (image_desc == NULL) {
|
||||
wl_resource_post_error(cm_surface_resource,
|
||||
WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_IMAGE_DESCRIPTION,
|
||||
"Image description to be set is invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < cm_surface->manager->render_intents_len; i++) {
|
||||
if (cm_surface->manager->render_intents[i] == render_intent) {
|
||||
|
|
@ -677,29 +666,35 @@ static void manager_handle_get_output(struct wl_client *client,
|
|||
struct wlr_color_manager_v1 *manager = manager_from_resource(manager_resource);
|
||||
struct wlr_output *output = wlr_output_from_resource(output_resource);
|
||||
|
||||
uint32_t version = wl_resource_get_version(manager_resource);
|
||||
struct wl_resource *cm_output_resource = wl_resource_create(client,
|
||||
&wp_color_management_output_v1_interface, version, id);
|
||||
if (!cm_output_resource) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(cm_output_resource, &cm_output_impl,
|
||||
NULL, cm_output_handle_resource_destroy);
|
||||
|
||||
if (output == NULL) {
|
||||
return; // leave the wp_color_management_output_v1 resource inert
|
||||
}
|
||||
|
||||
struct wlr_color_management_output_v1 *cm_output = calloc(1, sizeof(*cm_output));
|
||||
if (cm_output == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
|
||||
cm_output->resource = cm_output_resource;
|
||||
cm_output->manager = manager;
|
||||
|
||||
uint32_t version = wl_resource_get_version(manager_resource);
|
||||
cm_output->resource = wl_resource_create(client,
|
||||
&wp_color_management_output_v1_interface, version, id);
|
||||
if (!cm_output->resource) {
|
||||
wl_client_post_no_memory(client);
|
||||
free(cm_output);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(cm_output->resource, &cm_output_impl,
|
||||
cm_output, cm_output_handle_resource_destroy);
|
||||
cm_output->output = output;
|
||||
|
||||
cm_output->output_destroy.notify = cm_output_handle_output_destroy;
|
||||
wl_signal_add(&output->events.destroy, &cm_output->output_destroy);
|
||||
|
||||
wl_list_insert(&manager->outputs, &cm_output->link);
|
||||
wl_resource_set_user_data(cm_output->resource, cm_output);
|
||||
}
|
||||
|
||||
static struct wlr_color_management_surface_v1 *cm_surface_from_surface(struct wlr_surface *surface) {
|
||||
|
|
@ -782,7 +777,7 @@ static void manager_handle_get_surface_feedback(struct wl_client *client,
|
|||
|
||||
surface_feedback->surface = surface;
|
||||
surface_feedback->data = (struct wlr_image_description_v1_data){
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
|
||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
|
||||
.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
|
||||
};
|
||||
|
||||
|
|
@ -892,6 +887,8 @@ static void manager_bind(struct wl_client *client, void *data,
|
|||
|
||||
static void manager_handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_color_manager_v1 *manager = wl_container_of(listener, manager, display_destroy);
|
||||
wl_signal_emit_mutable(&manager->events.destroy, NULL);
|
||||
assert(wl_list_empty(&manager->events.destroy.listener_list));
|
||||
wl_list_remove(&manager->display_destroy.link);
|
||||
wl_global_destroy(manager->global);
|
||||
free(manager->render_intents);
|
||||
|
|
@ -939,6 +936,7 @@ struct wlr_color_manager_v1 *wlr_color_manager_v1_create(struct wl_display *disp
|
|||
manager->transfer_functions_len = options->transfer_functions_len;
|
||||
manager->primaries_len = options->primaries_len;
|
||||
|
||||
wl_signal_init(&manager->events.destroy);
|
||||
wl_list_init(&manager->outputs);
|
||||
wl_list_init(&manager->surface_feedbacks);
|
||||
|
||||
|
|
@ -985,3 +983,61 @@ void wlr_color_manager_v1_set_surface_preferred_image_description(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum wlr_color_transfer_function
|
||||
wlr_color_manager_v1_transfer_function_to_wlr(enum wp_color_manager_v1_transfer_function tf) {
|
||||
switch (tf) {
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB:
|
||||
return WLR_COLOR_TRANSFER_FUNCTION_SRGB;
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
return WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
return WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22:
|
||||
return WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886:
|
||||
return WLR_COLOR_TRANSFER_FUNCTION_BT1886;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
enum wp_color_manager_v1_transfer_function
|
||||
wlr_color_manager_v1_transfer_function_from_wlr(enum wlr_color_transfer_function tf) {
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
enum wlr_color_named_primaries
|
||||
wlr_color_manager_v1_primaries_to_wlr(enum wp_color_manager_v1_primaries primaries) {
|
||||
switch (primaries) {
|
||||
case WP_COLOR_MANAGER_V1_PRIMARIES_SRGB:
|
||||
return WLR_COLOR_NAMED_PRIMARIES_SRGB;
|
||||
case WP_COLOR_MANAGER_V1_PRIMARIES_BT2020:
|
||||
return WLR_COLOR_NAMED_PRIMARIES_BT2020;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
enum wp_color_manager_v1_primaries
|
||||
wlr_color_manager_v1_primaries_from_wlr(enum wlr_color_named_primaries primaries) {
|
||||
switch (primaries) {
|
||||
case WLR_COLOR_NAMED_PRIMARIES_SRGB:
|
||||
return WP_COLOR_MANAGER_V1_PRIMARIES_SRGB;
|
||||
case WLR_COLOR_NAMED_PRIMARIES_BT2020:
|
||||
return WP_COLOR_MANAGER_V1_PRIMARIES_BT2020;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -370,9 +370,11 @@ struct wlr_color_representation_manager_v1 *wlr_color_representation_manager_v1_
|
|||
ok &= memdup(&manager->supported_alpha_modes,
|
||||
options->supported_alpha_modes,
|
||||
sizeof(options->supported_alpha_modes[0]) * options->supported_alpha_modes_len);
|
||||
manager->supported_alpha_modes_len = options->supported_alpha_modes_len;
|
||||
ok &= memdup(&manager->supported_coeffs_and_ranges,
|
||||
options->supported_coeffs_and_ranges,
|
||||
sizeof(options->supported_coeffs_and_ranges[0]) * options->supported_coeffs_and_ranges_len);
|
||||
manager->supported_coeffs_and_ranges_len = options->supported_coeffs_and_ranges_len;
|
||||
if (!ok) {
|
||||
goto err_options;
|
||||
}
|
||||
|
|
@ -384,6 +386,8 @@ struct wlr_color_representation_manager_v1 *wlr_color_representation_manager_v1_
|
|||
goto err_options;
|
||||
}
|
||||
|
||||
wl_signal_init(&manager->events.destroy);
|
||||
|
||||
manager->display_destroy.notify = handle_display_destroy;
|
||||
wl_display_add_destroy_listener(display, &manager->display_destroy);
|
||||
|
||||
|
|
|
|||
|
|
@ -882,11 +882,7 @@ void wlr_surface_reject_pending(struct wlr_surface *surface, struct wl_resource
|
|||
va_list args;
|
||||
va_start(args, msg);
|
||||
|
||||
// XXX: libwayland could expose wl_resource_post_error_vargs() instead
|
||||
char buffer[128]; // Matches the size of the buffer used in libwayland
|
||||
vsnprintf(buffer, sizeof(buffer), msg, args);
|
||||
|
||||
wl_resource_post_error(resource, code, "%s", buffer);
|
||||
wl_resource_post_error_vargs(resource, code, msg, args);
|
||||
surface->pending_rejected = true;
|
||||
|
||||
va_end(args);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
#include <wlr/types/wlr_content_type_v1.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
|
||||
#include "content-type-v1-protocol.h"
|
||||
|
||||
#define CONTENT_TYPE_VERSION 1
|
||||
|
||||
struct wlr_content_type_v1_surface {
|
||||
|
|
|
|||
|
|
@ -530,10 +530,6 @@ static void cursor_output_cursor_update(struct wlr_cursor_output_cursor *output_
|
|||
struct wlr_cursor *cur = output_cursor->cursor;
|
||||
struct wlr_output *output = output_cursor->output_cursor->output;
|
||||
|
||||
if (!output->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor_output_cursor_reset_image(output_cursor);
|
||||
|
||||
if (cur->state->buffer != NULL) {
|
||||
|
|
@ -589,10 +585,11 @@ static void cursor_output_cursor_update(struct wlr_cursor_output_cursor *output_
|
|||
&src_box, dst_width, dst_height, surface->current.transform,
|
||||
hotspot_x, hotspot_y, wait_timeline, wait_point);
|
||||
|
||||
if (syncobj_surface_state != NULL && surface->buffer != NULL &&
|
||||
if (syncobj_surface_state != NULL &&
|
||||
surface->buffer != NULL && surface->buffer->source != NULL &&
|
||||
(surface->current.committed & WLR_SURFACE_STATE_BUFFER)) {
|
||||
wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(syncobj_surface_state,
|
||||
&surface->buffer->base);
|
||||
surface->buffer->source);
|
||||
}
|
||||
|
||||
if (output_cursor->output_cursor->visible) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
#include <wlr/types/wlr_cursor_shape_v1.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/types/wlr_tablet_tool.h>
|
||||
|
||||
#include "cursor-shape-v1-protocol.h"
|
||||
#include "types/wlr_tablet_v2.h"
|
||||
|
||||
#define CURSOR_SHAPE_MANAGER_V1_VERSION 2
|
||||
|
|
|
|||
|
|
@ -68,10 +68,6 @@ static void drm_lease_connector_v1_destroy(
|
|||
|
||||
wlr_log(WLR_DEBUG, "Destroying connector %s", connector->output->name);
|
||||
|
||||
if (connector->active_lease) {
|
||||
wlr_drm_lease_terminate(connector->active_lease->drm_lease);
|
||||
}
|
||||
|
||||
struct wl_resource *resource, *tmp;
|
||||
wl_resource_for_each_safe(resource, tmp, &connector->resources) {
|
||||
wp_drm_lease_connector_v1_send_withdrawn(resource);
|
||||
|
|
@ -140,14 +136,9 @@ static void lease_handle_destroy(struct wl_listener *listener, void *data) {
|
|||
|
||||
wl_list_remove(&lease->destroy.link);
|
||||
|
||||
for (size_t i = 0; i < lease->n_connectors; ++i) {
|
||||
lease->connectors[i]->active_lease = NULL;
|
||||
}
|
||||
|
||||
wl_list_remove(&lease->link);
|
||||
wl_resource_set_user_data(lease->resource, NULL);
|
||||
|
||||
free(lease->connectors);
|
||||
free(lease);
|
||||
}
|
||||
|
||||
|
|
@ -180,20 +171,6 @@ struct wlr_drm_lease_v1 *wlr_drm_lease_request_v1_grant(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
lease->connectors = calloc(request->n_connectors, sizeof(*lease->connectors));
|
||||
if (!lease->connectors) {
|
||||
wlr_log(WLR_ERROR, "Failed to allocate lease connectors list");
|
||||
close(fd);
|
||||
wp_drm_lease_v1_send_finished(lease->resource);
|
||||
free(lease);
|
||||
return NULL;
|
||||
}
|
||||
lease->n_connectors = request->n_connectors;
|
||||
for (size_t i = 0; i < request->n_connectors; ++i) {
|
||||
lease->connectors[i] = request->connectors[i];
|
||||
lease->connectors[i]->active_lease = lease;
|
||||
}
|
||||
|
||||
lease->destroy.notify = lease_handle_destroy;
|
||||
wl_signal_add(&lease->drm_lease->events.destroy, &lease->destroy);
|
||||
|
||||
|
|
@ -338,16 +315,6 @@ static void drm_lease_request_v1_handle_submit(
|
|||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < request->n_connectors; ++i) {
|
||||
struct wlr_drm_lease_connector_v1 *conn = request->connectors[i];
|
||||
if (conn->active_lease) {
|
||||
wlr_log(WLR_ERROR, "Failed to create lease, connector %s has "
|
||||
"already been leased", conn->output->name);
|
||||
wp_drm_lease_v1_send_finished(lease_resource);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
request->lease_resource = lease_resource;
|
||||
|
||||
wl_signal_emit_mutable(&request->device->manager->events.request,
|
||||
|
|
@ -440,10 +407,6 @@ static struct wp_drm_lease_connector_v1_interface lease_connector_impl = {
|
|||
static void drm_lease_connector_v1_send_to_client(
|
||||
struct wlr_drm_lease_connector_v1 *connector,
|
||||
struct wl_resource *resource) {
|
||||
if (connector->active_lease) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wl_client *client = wl_resource_get_client(resource);
|
||||
|
||||
uint32_t version = wl_resource_get_version(resource);
|
||||
|
|
@ -490,10 +453,12 @@ static void lease_device_bind(struct wl_client *wl_client, void *data,
|
|||
if (!device) {
|
||||
wlr_log(WLR_DEBUG, "Failed to bind lease device, "
|
||||
"the wlr_drm_lease_device_v1 has been destroyed");
|
||||
wl_list_init(wl_resource_get_link(device_resource));
|
||||
return;
|
||||
}
|
||||
|
||||
wl_resource_set_user_data(device_resource, device);
|
||||
wl_list_insert(&device->resources, wl_resource_get_link(device_resource));
|
||||
|
||||
int fd = wlr_drm_backend_get_non_master_fd(device->backend);
|
||||
if (fd < 0) {
|
||||
|
|
@ -505,8 +470,6 @@ static void lease_device_bind(struct wl_client *wl_client, void *data,
|
|||
wp_drm_lease_device_v1_send_drm_fd(device_resource, fd);
|
||||
close(fd);
|
||||
|
||||
wl_list_insert(&device->resources, wl_resource_get_link(device_resource));
|
||||
|
||||
struct wlr_drm_lease_connector_v1 *connector;
|
||||
wl_list_for_each(connector, &device->connectors, link) {
|
||||
drm_lease_connector_v1_send_to_client(connector, device_resource);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include "ext-image-copy-capture-v1-protocol.h"
|
||||
#include "render/pixel_format.h"
|
||||
|
||||
#define IMAGE_COPY_CAPTURE_MANAGER_V1_VERSION 1
|
||||
|
|
|
|||
65
types/wlr_fixes.c
Normal file
65
types/wlr_fixes.c
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#include <assert.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <wlr/types/wlr_fixes.h>
|
||||
|
||||
#define FIXES_VERSION 1
|
||||
|
||||
static void fixes_destroy(struct wl_client *client, struct wl_resource *resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void fixes_destroy_registry(struct wl_client *client, struct wl_resource *resource,
|
||||
struct wl_resource *registry) {
|
||||
wl_resource_destroy(registry);
|
||||
}
|
||||
|
||||
static const struct wl_fixes_interface fixes_impl = {
|
||||
.destroy = fixes_destroy,
|
||||
.destroy_registry = fixes_destroy_registry,
|
||||
};
|
||||
|
||||
static void fixes_bind(struct wl_client *wl_client, void *data, uint32_t version, uint32_t id) {
|
||||
struct wlr_fixes *fixes = data;
|
||||
|
||||
struct wl_resource *resource = wl_resource_create(wl_client, &wl_fixes_interface, version, id);
|
||||
if (resource == NULL) {
|
||||
wl_client_post_no_memory(wl_client);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(resource, &fixes_impl, fixes, NULL);
|
||||
}
|
||||
|
||||
static void fixes_handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_fixes *fixes = wl_container_of(listener, fixes, display_destroy);
|
||||
wl_signal_emit_mutable(&fixes->events.destroy, NULL);
|
||||
|
||||
assert(wl_list_empty(&fixes->events.destroy.listener_list));
|
||||
|
||||
wl_list_remove(&fixes->display_destroy.link);
|
||||
wl_global_destroy(fixes->global);
|
||||
free(fixes);
|
||||
}
|
||||
|
||||
struct wlr_fixes *wlr_fixes_create(struct wl_display *display, uint32_t version) {
|
||||
assert(version <= FIXES_VERSION);
|
||||
|
||||
struct wlr_fixes *fixes = calloc(1, sizeof(*fixes));
|
||||
if (fixes == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fixes->global = wl_global_create(display, &wl_fixes_interface, version, fixes, fixes_bind);
|
||||
if (fixes->global == NULL) {
|
||||
free(fixes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wl_signal_init(&fixes->events.destroy);
|
||||
|
||||
fixes->display_destroy.notify = fixes_handle_display_destroy;
|
||||
wl_display_add_destroy_listener(display, &fixes->display_destroy);
|
||||
|
||||
return fixes;
|
||||
}
|
||||
|
|
@ -157,6 +157,9 @@ static void gamma_control_manager_get_gamma_control(struct wl_client *client,
|
|||
}
|
||||
|
||||
size_t gamma_size = wlr_output_get_gamma_size(output);
|
||||
if (gamma_size == 0) {
|
||||
gamma_size = manager->fallback_gamma_size;
|
||||
}
|
||||
if (gamma_size == 0) {
|
||||
zwlr_gamma_control_v1_send_failed(resource);
|
||||
return;
|
||||
|
|
@ -262,15 +265,24 @@ struct wlr_gamma_control_v1 *wlr_gamma_control_manager_v1_get_control(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_color_transform *wlr_gamma_control_v1_get_color_transform(
|
||||
struct wlr_gamma_control_v1 *gamma_control) {
|
||||
if (gamma_control == NULL || gamma_control->table == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint16_t *r = gamma_control->table;
|
||||
const uint16_t *g = gamma_control->table + gamma_control->ramp_size;
|
||||
const uint16_t *b = gamma_control->table + 2 * gamma_control->ramp_size;
|
||||
|
||||
return wlr_color_transform_init_lut_3x1d(gamma_control->ramp_size, r, g, b);
|
||||
}
|
||||
|
||||
bool wlr_gamma_control_v1_apply(struct wlr_gamma_control_v1 *gamma_control,
|
||||
struct wlr_output_state *output_state) {
|
||||
struct wlr_color_transform *tr = NULL;
|
||||
if (gamma_control != NULL && gamma_control->table != NULL) {
|
||||
const uint16_t *r = gamma_control->table;
|
||||
const uint16_t *g = gamma_control->table + gamma_control->ramp_size;
|
||||
const uint16_t *b = gamma_control->table + 2 * gamma_control->ramp_size;
|
||||
|
||||
tr = wlr_color_transform_init_lut_3x1d(gamma_control->ramp_size, r, g, b);
|
||||
tr = wlr_gamma_control_v1_get_color_transform(gamma_control);
|
||||
if (tr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ static void input_method_destroy(struct wlr_input_method_v2 *input_method) {
|
|||
popup_surface, tmp, &input_method->popup_surfaces, link) {
|
||||
popup_surface_destroy(popup_surface);
|
||||
}
|
||||
wl_signal_emit_mutable(&input_method->events.destroy, input_method);
|
||||
wlr_input_method_keyboard_grab_v2_destroy(input_method->keyboard_grab);
|
||||
wl_signal_emit_mutable(&input_method->events.destroy, NULL);
|
||||
|
||||
assert(wl_list_empty(&input_method->events.commit.listener_list));
|
||||
assert(wl_list_empty(&input_method->events.new_popup_surface.listener_list));
|
||||
|
|
@ -65,7 +66,6 @@ static void input_method_destroy(struct wlr_input_method_v2 *input_method) {
|
|||
|
||||
wl_list_remove(wl_resource_get_link(input_method->resource));
|
||||
wl_list_remove(&input_method->seat_client_destroy.link);
|
||||
wlr_input_method_keyboard_grab_v2_destroy(input_method->keyboard_grab);
|
||||
input_state_reset(&input_method->pending);
|
||||
input_state_reset(&input_method->current);
|
||||
free(input_method);
|
||||
|
|
@ -102,7 +102,7 @@ static void im_commit(struct wl_client *client, struct wl_resource *resource,
|
|||
input_method->current = input_method->pending;
|
||||
input_method->pending = (struct wlr_input_method_v2_state){0};
|
||||
|
||||
wl_signal_emit_mutable(&input_method->events.commit, input_method);
|
||||
wl_signal_emit_mutable(&input_method->events.commit, NULL);
|
||||
}
|
||||
|
||||
static void im_commit_string(struct wl_client *client,
|
||||
|
|
@ -271,8 +271,7 @@ void wlr_input_method_keyboard_grab_v2_destroy(
|
|||
if (!keyboard_grab) {
|
||||
return;
|
||||
}
|
||||
wl_signal_emit_mutable(&keyboard_grab->events.destroy, keyboard_grab);
|
||||
|
||||
wl_signal_emit_mutable(&keyboard_grab->events.destroy, NULL);
|
||||
assert(wl_list_empty(&keyboard_grab->events.destroy.listener_list));
|
||||
|
||||
keyboard_grab->input_method->keyboard_grab = NULL;
|
||||
|
|
@ -575,7 +574,7 @@ static void manager_get_input_method(struct wl_client *client,
|
|||
wl_resource_set_user_data(im_resource, input_method);
|
||||
wl_list_insert(&im_manager->input_methods,
|
||||
wl_resource_get_link(input_method->resource));
|
||||
wl_signal_emit_mutable(&im_manager->events.input_method, input_method);
|
||||
wl_signal_emit_mutable(&im_manager->events.new_input_method, input_method);
|
||||
}
|
||||
|
||||
static void manager_destroy(struct wl_client *client,
|
||||
|
|
@ -606,9 +605,9 @@ static void input_method_manager_bind(struct wl_client *wl_client, void *data,
|
|||
static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_input_method_manager_v2 *manager =
|
||||
wl_container_of(listener, manager, display_destroy);
|
||||
wl_signal_emit_mutable(&manager->events.destroy, manager);
|
||||
wl_signal_emit_mutable(&manager->events.destroy, NULL);
|
||||
|
||||
assert(wl_list_empty(&manager->events.input_method.listener_list));
|
||||
assert(wl_list_empty(&manager->events.new_input_method.listener_list));
|
||||
assert(wl_list_empty(&manager->events.destroy.listener_list));
|
||||
|
||||
wl_list_remove(&manager->display_destroy.link);
|
||||
|
|
@ -623,7 +622,7 @@ struct wlr_input_method_manager_v2 *wlr_input_method_manager_v2_create(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
wl_signal_init(&im_manager->events.input_method);
|
||||
wl_signal_init(&im_manager->events.new_input_method);
|
||||
wl_signal_init(&im_manager->events.destroy);
|
||||
|
||||
wl_list_init(&im_manager->input_methods);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ struct wlr_linux_drm_syncobj_surface_v1 {
|
|||
};
|
||||
|
||||
struct wlr_linux_drm_syncobj_surface_v1_commit {
|
||||
struct wlr_linux_drm_syncobj_surface_v1 *surface;
|
||||
struct wlr_surface *surface;
|
||||
struct wlr_drm_syncobj_timeline_waiter waiter;
|
||||
uint32_t cached_seq;
|
||||
|
||||
|
|
@ -192,7 +192,7 @@ static struct wlr_linux_drm_syncobj_surface_v1 *surface_from_wlr_surface(
|
|||
}
|
||||
|
||||
static void surface_commit_destroy(struct wlr_linux_drm_syncobj_surface_v1_commit *commit) {
|
||||
wlr_surface_unlock_cached(commit->surface->surface, commit->cached_seq);
|
||||
wlr_surface_unlock_cached(commit->surface, commit->cached_seq);
|
||||
wl_list_remove(&commit->surface_destroy.link);
|
||||
wlr_drm_syncobj_timeline_waiter_finish(&commit->waiter);
|
||||
free(commit);
|
||||
|
|
@ -237,7 +237,7 @@ static bool lock_surface_commit(struct wlr_linux_drm_syncobj_surface_v1 *surface
|
|||
return false;
|
||||
}
|
||||
|
||||
commit->surface = surface;
|
||||
commit->surface = surface->surface;
|
||||
commit->cached_seq = wlr_surface_lock_pending(surface->surface);
|
||||
|
||||
commit->surface_destroy.notify = surface_commit_handle_surface_destroy;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include "pointer-constraints-unstable-v1-protocol.h"
|
||||
|
||||
static const struct zwp_locked_pointer_v1_interface locked_pointer_impl;
|
||||
static const struct zwp_confined_pointer_v1_interface confined_pointer_impl;
|
||||
static const struct zwp_pointer_constraints_v1_interface pointer_constraints_impl;
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ static void manager_handle_create_icon(struct wl_client *client, struct wl_resou
|
|||
|
||||
struct wl_resource *icon_resource = wl_resource_create(client,
|
||||
&xdg_toplevel_icon_v1_interface, wl_resource_get_version(resource), id);
|
||||
if (resource == NULL) {
|
||||
if (icon_resource == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
free(icon);
|
||||
return;
|
||||
|
|
|
|||
13
util/box.c
13
util/box.c
|
|
@ -19,16 +19,15 @@ void wlr_box_closest_point(const struct wlr_box *box, double x, double y,
|
|||
//
|
||||
// In order to be consistent with e.g. wlr_box_contains_point(),
|
||||
// this function returns a point inside the bottom and right edges
|
||||
// of the box by at least 1/65536 of a unit (pixel). 1/65536 is
|
||||
// of the box by at least 1/256 of a unit (pixel). 1/256 is
|
||||
// small enough to avoid a "dead zone" with high-resolution mice
|
||||
// but large enough to avoid rounding to zero (due to loss of
|
||||
// significant digits) in simple floating-point calculations.
|
||||
// but large enough to avoid rounding to zero in wl_fixed_from_double().
|
||||
|
||||
// find the closest x point
|
||||
if (x < box->x) {
|
||||
*dest_x = box->x;
|
||||
} else if (x > box->x + box->width - 1/65536.0) {
|
||||
*dest_x = box->x + box->width - 1/65536.0;
|
||||
} else if (x > box->x + box->width - 1/256.0) {
|
||||
*dest_x = box->x + box->width - 1/256.0;
|
||||
} else {
|
||||
*dest_x = x;
|
||||
}
|
||||
|
|
@ -36,8 +35,8 @@ void wlr_box_closest_point(const struct wlr_box *box, double x, double y,
|
|||
// find closest y point
|
||||
if (y < box->y) {
|
||||
*dest_y = box->y;
|
||||
} else if (y > box->y + box->height - 1/65536.0) {
|
||||
*dest_y = box->y + box->height - 1/65536.0;
|
||||
} else if (y > box->y + box->height - 1/256.0) {
|
||||
*dest_y = box->y + box->height - 1/256.0;
|
||||
} else {
|
||||
*dest_y = y;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ wlr_files += files(
|
|||
'matrix.c',
|
||||
'mem.c',
|
||||
'rect_union.c',
|
||||
'rectpack.c',
|
||||
'region.c',
|
||||
'set.c',
|
||||
'shm.c',
|
||||
|
|
|
|||
533
util/rectpack.c
Normal file
533
util/rectpack.c
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/util/rectpack.h>
|
||||
|
||||
struct wlr_rectpack_bandbuf {
|
||||
pixman_box32_t *data;
|
||||
size_t len;
|
||||
size_t cap;
|
||||
};
|
||||
|
||||
static void bandbuf_init(struct wlr_rectpack_bandbuf *buf) {
|
||||
*buf = (struct wlr_rectpack_bandbuf){0};
|
||||
}
|
||||
|
||||
static void bandbuf_finish(struct wlr_rectpack_bandbuf *buf) {
|
||||
free(buf->data);
|
||||
}
|
||||
|
||||
static bool bandbuf_add(struct wlr_rectpack_bandbuf *buf, pixman_box32_t *band) {
|
||||
if (buf->len == buf->cap) {
|
||||
buf->cap = buf->cap == 0 ? 32 : buf->cap * 2;
|
||||
pixman_box32_t *data = realloc(buf->data, sizeof(*data) * buf->cap);
|
||||
if (data == NULL) {
|
||||
return false;
|
||||
}
|
||||
buf->data = data;
|
||||
}
|
||||
buf->data[buf->len++] = *band;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool lines_overlap(int a1, int b1, int a2, int b2) {
|
||||
int max_a = a1 > a2 ? a1 : a2;
|
||||
int min_b = b1 < b2 ? b1 : b2;
|
||||
return min_b > max_a;
|
||||
}
|
||||
|
||||
// Returns false if the constraint overlaps with the origin
|
||||
static bool line_crop(int *a, int *b, int exclusive_a, int exclusive_b,
|
||||
int origin_a, int origin_b) {
|
||||
if (exclusive_a >= origin_b) {
|
||||
if (*b > exclusive_a) {
|
||||
*b = exclusive_a;
|
||||
}
|
||||
} else if (exclusive_b <= origin_a) {
|
||||
if (*a < exclusive_b) {
|
||||
*a = exclusive_b;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns false on memory allocation error
|
||||
static bool grow_2d(const struct wlr_box *bounds, pixman_region32_t *exclusive,
|
||||
pixman_box32_t *target) {
|
||||
// The goal is to find the largest empty rectangle within the exclusive region such that it
|
||||
// would contain the target rectangle. To achieve this, we split the remaining empty space into
|
||||
// horizontal bands in such a way that they form two trapezoids (top and bottom), and then
|
||||
// iterate over pairs of bands from each trapezoid to find the largest rectangle.
|
||||
|
||||
// Note: Pixman regions are stored as sorted "y-x-banded" arrays of rectangles. For
|
||||
// implementation details, see pixman-region.c.
|
||||
|
||||
int n_exclusive_rects;
|
||||
pixman_box32_t *exclusive_rects = pixman_region32_rectangles(exclusive, &n_exclusive_rects);
|
||||
|
||||
// Step 1: find the middle band, split the exclusive region in 3 subregions:
|
||||
// - above the target;
|
||||
// - vertically overlapping with the target;
|
||||
// - below the target.
|
||||
|
||||
// The widest band, contains the target
|
||||
pixman_box32_t mid_band = (pixman_box32_t){
|
||||
.x1 = bounds->x,
|
||||
.y1 = bounds->y,
|
||||
.x2 = bounds->x + bounds->width,
|
||||
.y2 = bounds->y + bounds->height,
|
||||
};
|
||||
|
||||
// Find exclusive rectangles which are above the target, crop the middle band from the top
|
||||
int above_rect_i = 0;
|
||||
for (; above_rect_i < n_exclusive_rects; above_rect_i++) {
|
||||
pixman_box32_t *rect = &exclusive_rects[above_rect_i];
|
||||
if (rect->y2 > target->y1) {
|
||||
break;
|
||||
}
|
||||
mid_band.y1 = rect->y2;
|
||||
}
|
||||
|
||||
// Find exclusive rectangles which vertically overlap with the target, crop the middle band from
|
||||
// the other sides
|
||||
int below_rect_i = above_rect_i--;
|
||||
for (; below_rect_i < n_exclusive_rects; below_rect_i++) {
|
||||
pixman_box32_t *rect = &exclusive_rects[below_rect_i];
|
||||
if (rect->y1 >= target->y2) {
|
||||
mid_band.y2 = rect->y1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Invariant: no exclusive rectangle overlaps with the minimum box
|
||||
line_crop(&mid_band.x1, &mid_band.x2, rect->x1, rect->x2, target->x1, target->x2);
|
||||
}
|
||||
|
||||
// The rest of the exclusive rectangles are below the target
|
||||
|
||||
// Step 2: find the rest of the bands.
|
||||
|
||||
bool ok = false;
|
||||
|
||||
struct wlr_rectpack_bandbuf bandbuf;
|
||||
bandbuf_init(&bandbuf);
|
||||
|
||||
|
||||
// Find all "above" bands, moving up from the middle
|
||||
// Note: this includes the middle band itself
|
||||
if (!bandbuf_add(&bandbuf, &mid_band)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
while (above_rect_i >= 0) {
|
||||
pixman_box32_t *rect = &exclusive_rects[above_rect_i];
|
||||
pixman_box32_t *last = &bandbuf.data[bandbuf.len - 1];
|
||||
|
||||
// Invariant: a band farther from the middle one is horizontally contained by a band closer
|
||||
// to the middle one
|
||||
pixman_box32_t band = {
|
||||
.x1 = last->x1,
|
||||
.y1 = rect->y1,
|
||||
.x2 = last->x2,
|
||||
.y2 = rect->y2,
|
||||
};
|
||||
// Extend the last one up in case of free vertical space
|
||||
last->y1 = band.y2;
|
||||
|
||||
// Process the x-band of exclusive rectangles
|
||||
do {
|
||||
if (!line_crop(&band.x1, &band.x2, rect->x1, rect->x2, target->x1, target->x2)) {
|
||||
// A rectangle is horizontally overlapping with the target; it's not possible to go
|
||||
// further
|
||||
goto above_done;
|
||||
} else if (above_rect_i-- == 0) {
|
||||
// All rectangles processed
|
||||
break;
|
||||
}
|
||||
rect = &exclusive_rects[above_rect_i];
|
||||
} while (rect->y1 == band.y1);
|
||||
|
||||
if (band.x1 == last->x1 && band.x2 == last->x2) {
|
||||
// Horizontally equal to the last; extend that up instead
|
||||
last->y1 = band.y1;
|
||||
} else {
|
||||
if (!bandbuf_add(&bandbuf, &band)) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Extend the last one up in case of free vertical space
|
||||
bandbuf.data[bandbuf.len - 1].y1 = bounds->y;
|
||||
above_done:;
|
||||
|
||||
size_t split_i = bandbuf.len;
|
||||
|
||||
// Find all "below" bands, moving down from the middle
|
||||
// Same logic applies
|
||||
|
||||
if (!bandbuf_add(&bandbuf, &mid_band)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
while (below_rect_i < n_exclusive_rects) {
|
||||
pixman_box32_t *rect = &exclusive_rects[below_rect_i];
|
||||
pixman_box32_t *last = &bandbuf.data[bandbuf.len - 1];
|
||||
|
||||
pixman_box32_t band = {
|
||||
.x1 = last->x1,
|
||||
.y1 = rect->y1,
|
||||
.x2 = last->x2,
|
||||
.y2 = rect->y2,
|
||||
};
|
||||
last->y2 = band.y1;
|
||||
|
||||
do {
|
||||
if (!line_crop(&band.x1, &band.x2, rect->x1, rect->x2, target->x1, target->x2)) {
|
||||
goto below_done;
|
||||
} else if (++below_rect_i == n_exclusive_rects) {
|
||||
break;
|
||||
}
|
||||
rect = &exclusive_rects[below_rect_i];
|
||||
} while (rect->y1 == band.y1);
|
||||
|
||||
if (band.x1 == last->x1 && band.x2 == last->x2) {
|
||||
last->y2 = band.y2;
|
||||
} else {
|
||||
if (!bandbuf_add(&bandbuf, &band)) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
bandbuf.data[bandbuf.len - 1].y2 = bounds->y + bounds->height;
|
||||
below_done:;
|
||||
|
||||
// Step 3: find the largest rectangle within the empty bands. Between rectangles with the same
|
||||
// area, pick the one that uses the smaller bounds space better; i.e. pick a "more vertical"
|
||||
// rectangle within horizontal bounds and vice versa.
|
||||
|
||||
bool bounds_horizontal = bounds->width > bounds->height;
|
||||
int best_area = (target->x2 - target->x1) * (target->y2 - target->y1);
|
||||
|
||||
// Note: the (mid_band, mid_band) pair is checked too
|
||||
for (size_t above_i = 0; above_i < split_i; above_i++) {
|
||||
pixman_box32_t *above = &bandbuf.data[above_i];
|
||||
for (size_t below_i = split_i; below_i < bandbuf.len; below_i++) {
|
||||
pixman_box32_t *below = &bandbuf.data[below_i];
|
||||
|
||||
pixman_box32_t curr = {
|
||||
.x1 = above->x1 > below->x1 ? above->x1 : below->x1,
|
||||
.y1 = above->y1,
|
||||
.x2 = above->x2 < below->x2 ? above->x2 : below->x2,
|
||||
.y2 = below->y2,
|
||||
};
|
||||
|
||||
int width = curr.x2 - curr.x1, height = curr.y2 - curr.y1;
|
||||
int area = width * height;
|
||||
if (area > best_area || (area == best_area && bounds_horizontal != (width > height))) {
|
||||
*target = curr;
|
||||
best_area = area;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ok = true;
|
||||
|
||||
end:
|
||||
bandbuf_finish(&bandbuf);
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool wlr_rectpack_place(const struct wlr_box *bounds, pixman_region32_t *exclusive,
|
||||
const struct wlr_box *box, struct wlr_rectpack_rules *rules, struct wlr_box *out) {
|
||||
assert(!wlr_box_empty(box));
|
||||
|
||||
if (bounds->width < box->width || bounds->height < box->height) {
|
||||
// Trivial case: the bounds are not big enough for the minimum box
|
||||
return false;
|
||||
}
|
||||
|
||||
int n_exclusive_rects = 0;
|
||||
pixman_box32_t *exclusive_rects = NULL;
|
||||
if (exclusive != NULL) {
|
||||
exclusive_rects = pixman_region32_rectangles(exclusive, &n_exclusive_rects);
|
||||
}
|
||||
|
||||
if (n_exclusive_rects == 0) {
|
||||
// Trivial case: the exclusive region is empty or ignored, just stretch to bounds as needed
|
||||
if (rules->grow_width) {
|
||||
out->x = bounds->x;
|
||||
out->width = bounds->width;
|
||||
} else {
|
||||
out->x = box->x;
|
||||
out->width = box->width;
|
||||
}
|
||||
if (rules->grow_height) {
|
||||
out->y = bounds->y;
|
||||
out->height = bounds->height;
|
||||
} else {
|
||||
out->y = box->y;
|
||||
out->height = box->height;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 1: fit the minimum box within the exclusive region.
|
||||
|
||||
// Instead of trying to fit a min_width×min_height rectangle, shrink the available region and
|
||||
// try to fit a 1×1 rectangle.
|
||||
int dwidth = box->width - 1;
|
||||
int dheight = box->height - 1;
|
||||
|
||||
pixman_box32_t shrunk_bounds = {
|
||||
.x1 = bounds->x,
|
||||
.y1 = bounds->y,
|
||||
.x2 = bounds->x + bounds->width - dwidth,
|
||||
.y2 = bounds->y + bounds->height - dheight,
|
||||
};
|
||||
|
||||
pixman_region32_t available;
|
||||
pixman_region32_init(&available);
|
||||
|
||||
if (dwidth != 0 || dheight != 0) {
|
||||
pixman_box32_t *expanded_rects = calloc(n_exclusive_rects, sizeof(*expanded_rects));
|
||||
if (expanded_rects == NULL) {
|
||||
wlr_log(WLR_ERROR, "Allocation failed");
|
||||
pixman_region32_fini(&available);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_exclusive_rects; i++) {
|
||||
pixman_box32_t *rect = &exclusive_rects[i];
|
||||
expanded_rects[i] = (pixman_box32_t){
|
||||
.x1 = rect->x1 - dwidth,
|
||||
.y1 = rect->y1 - dheight,
|
||||
.x2 = rect->x2,
|
||||
.y2 = rect->y2,
|
||||
};
|
||||
}
|
||||
|
||||
pixman_region32_t expanded;
|
||||
pixman_region32_init_rects(&expanded, expanded_rects, n_exclusive_rects);
|
||||
pixman_region32_inverse(&available, &expanded, &shrunk_bounds);
|
||||
pixman_region32_fini(&expanded);
|
||||
|
||||
free(expanded_rects);
|
||||
} else {
|
||||
// Fast path: the minimum box is already 1×1
|
||||
pixman_region32_inverse(&available, exclusive, &shrunk_bounds);
|
||||
}
|
||||
|
||||
int n_available_rects;
|
||||
pixman_box32_t *available_rects = pixman_region32_rectangles(&available, &n_available_rects);
|
||||
if (n_available_rects == 0) {
|
||||
// Not enough free space within the exclusive region for the minimum box
|
||||
pixman_region32_fini(&available);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the position closest to the desired one
|
||||
int best_x = box->x, best_y = box->y;
|
||||
int best_dist_sq = INT_MAX;
|
||||
for (int i = 0; i < n_available_rects; i++) {
|
||||
pixman_box32_t *rect = &available_rects[i];
|
||||
int clamped_x = box->x < rect->x1 ? rect->x1 :
|
||||
box->x >= rect->x2 ? rect->x2 - 1 : box->x;
|
||||
int clamped_y = box->y < rect->y1 ? rect->y1 :
|
||||
box->y >= rect->y2 ? rect->y2 - 1 : box->y;
|
||||
|
||||
int dx = clamped_x - box->x, dy = clamped_y - box->y;
|
||||
int dist_sq = dx * dx + dy * dy;
|
||||
if (dist_sq < best_dist_sq) {
|
||||
best_dist_sq = dist_sq;
|
||||
best_x = clamped_x;
|
||||
best_y = clamped_y;
|
||||
}
|
||||
|
||||
if (best_dist_sq == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
pixman_region32_fini(&available);
|
||||
|
||||
// Step 2: grow the box as requested.
|
||||
|
||||
pixman_box32_t result = {
|
||||
.x1 = best_x,
|
||||
.y1 = best_y,
|
||||
.x2 = best_x + box->width,
|
||||
.y2 = best_y + box->height,
|
||||
};
|
||||
|
||||
if (rules->grow_width && rules->grow_height) {
|
||||
if (!grow_2d(bounds, exclusive, &result)) {
|
||||
return false;
|
||||
}
|
||||
} else if (rules->grow_width) {
|
||||
// Stretch and then crop
|
||||
int o1 = result.x1, o2 = result.x2;
|
||||
result.x1 = bounds->x;
|
||||
result.x2 = bounds->x + bounds->width;
|
||||
|
||||
for (int i = 0; i < n_exclusive_rects; i++) {
|
||||
pixman_box32_t *rect = &exclusive_rects[i];
|
||||
if (lines_overlap(result.y1, result.y2, rect->y1, rect->y2)) {
|
||||
// Invariant: no exclusive rectangle overlaps with the minimum box
|
||||
line_crop(&result.x1, &result.x2, rect->x1, rect->x2, o1, o2);
|
||||
}
|
||||
}
|
||||
} else if (rules->grow_height) {
|
||||
// Same as width
|
||||
int o1 = result.y1, o2 = result.y2;
|
||||
result.y1 = bounds->y;
|
||||
result.y2 = bounds->y + bounds->height;
|
||||
|
||||
for (int i = 0; i < n_exclusive_rects; i++) {
|
||||
pixman_box32_t *rect = &exclusive_rects[i];
|
||||
if (lines_overlap(result.x1, result.x2, rect->x1, rect->x2)) {
|
||||
// Invariant: no exclusive rectangle overlaps with the minimum box
|
||||
line_crop(&result.y1, &result.y2, rect->y1, rect->y2, o1, o2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*out = (struct wlr_box){
|
||||
.x = result.x1,
|
||||
.y = result.y1,
|
||||
.width = result.x2 - result.x1,
|
||||
.height = result.y2 - result.y1,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wlr_rectpack_place_wlr_layer_surface_v1(const struct wlr_box *bounds,
|
||||
pixman_region32_t *exclusive, struct wlr_layer_surface_v1 *surface, struct wlr_box *out) {
|
||||
struct wlr_layer_surface_v1_state *state = &surface->current;
|
||||
uint32_t anchor = state->anchor;
|
||||
|
||||
int m_top = anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP ? state->margin.top : 0;
|
||||
int m_bottom = anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ? state->margin.bottom : 0;
|
||||
int m_left = anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ? state->margin.left : 0;
|
||||
int m_right = anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT ? state->margin.right : 0;
|
||||
|
||||
int m_horiz = m_left + m_right;
|
||||
int m_verti = m_top + m_bottom;
|
||||
|
||||
enum wlr_edges exclusive_edge = wlr_layer_surface_v1_get_exclusive_edge(surface);
|
||||
int full_exclusive_zone = state->exclusive_zone;
|
||||
|
||||
switch (exclusive_edge) {
|
||||
case WLR_EDGE_LEFT:
|
||||
full_exclusive_zone += m_left;
|
||||
break;
|
||||
case WLR_EDGE_RIGHT:
|
||||
full_exclusive_zone += m_right;
|
||||
break;
|
||||
case WLR_EDGE_TOP:
|
||||
full_exclusive_zone += m_top;
|
||||
break;
|
||||
case WLR_EDGE_BOTTOM:
|
||||
full_exclusive_zone += m_bottom;
|
||||
break;
|
||||
case WLR_EDGE_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
int desired_width = (int)state->desired_width, desired_height = (int)state->desired_height;
|
||||
bool grow_width = desired_width == 0, grow_height = desired_height == 0;
|
||||
|
||||
int min_width = (grow_width ? 1 : desired_width) + m_horiz;
|
||||
int min_height = (grow_height ? 1 : desired_height) + m_verti;
|
||||
|
||||
if (min_width < 1) {
|
||||
min_width = 1;
|
||||
}
|
||||
if (min_height < 1) {
|
||||
min_height = 1;
|
||||
}
|
||||
|
||||
switch (exclusive_edge) {
|
||||
case WLR_EDGE_LEFT:
|
||||
case WLR_EDGE_RIGHT:
|
||||
if (min_width < full_exclusive_zone) {
|
||||
min_width = full_exclusive_zone;
|
||||
}
|
||||
break;
|
||||
case WLR_EDGE_TOP:
|
||||
case WLR_EDGE_BOTTOM:
|
||||
if (min_height < full_exclusive_zone) {
|
||||
min_height = full_exclusive_zone;
|
||||
}
|
||||
break;
|
||||
case WLR_EDGE_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t edges = anchor;
|
||||
if ((edges & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) == (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) {
|
||||
edges &= ~(WLR_EDGE_LEFT | WLR_EDGE_RIGHT);
|
||||
}
|
||||
if ((edges & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) == (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) {
|
||||
edges &= ~(WLR_EDGE_TOP | WLR_EDGE_BOTTOM);
|
||||
}
|
||||
|
||||
struct wlr_box box = {
|
||||
.x = bounds->x,
|
||||
.y = bounds->y,
|
||||
.width = min_width,
|
||||
.height = min_height,
|
||||
};
|
||||
|
||||
if ((anchor & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) == WLR_EDGE_RIGHT) {
|
||||
box.x += bounds->width - box.width;
|
||||
} else if ((anchor & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) != WLR_EDGE_LEFT) {
|
||||
box.x += bounds->width / 2 - box.width / 2;
|
||||
}
|
||||
if ((anchor & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) == WLR_EDGE_BOTTOM) {
|
||||
box.y += bounds->height - box.height;
|
||||
} else if ((anchor & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) != WLR_EDGE_TOP) {
|
||||
box.y += bounds->height / 2 - box.height / 2;
|
||||
}
|
||||
|
||||
struct wlr_rectpack_rules rules = {
|
||||
.grow_width = grow_width,
|
||||
.grow_height = grow_height,
|
||||
};
|
||||
|
||||
if (!wlr_rectpack_place(bounds, state->exclusive_zone >= 0 ? exclusive : NULL,
|
||||
&box, &rules, out)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exclusive_edge != WLR_EDGE_NONE) {
|
||||
struct wlr_box exclusive_box = *out;
|
||||
switch (exclusive_edge) {
|
||||
case WLR_EDGE_RIGHT:
|
||||
exclusive_box.x += out->width - full_exclusive_zone;
|
||||
// Fallthrough
|
||||
case WLR_EDGE_LEFT:
|
||||
exclusive_box.width = full_exclusive_zone;
|
||||
break;
|
||||
case WLR_EDGE_BOTTOM:
|
||||
exclusive_box.y += out->height - full_exclusive_zone;
|
||||
// Fallthrough
|
||||
case WLR_EDGE_TOP:
|
||||
exclusive_box.height = full_exclusive_zone;
|
||||
break;
|
||||
case WLR_EDGE_NONE:
|
||||
abort(); // Unreachable
|
||||
}
|
||||
|
||||
struct wlr_box intersection;
|
||||
if (wlr_box_intersection(&intersection, &exclusive_box, bounds)) {
|
||||
pixman_region32_union_rect(exclusive, exclusive, intersection.x,
|
||||
intersection.y, (unsigned int)intersection.width,
|
||||
(unsigned int)intersection.height);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -42,6 +42,9 @@ static void handle_server_start(struct wl_listener *listener, void *data) {
|
|||
static void xwayland_mark_ready(struct wlr_xwayland *xwayland) {
|
||||
assert(xwayland->server->wm_fd[0] >= 0);
|
||||
xwayland->xwm = xwm_create(xwayland, xwayland->server->wm_fd[0]);
|
||||
// xwm_create takes ownership of wm_fd[0] under all circumstances
|
||||
xwayland->server->wm_fd[0] = -1;
|
||||
|
||||
if (!xwayland->xwm) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -69,6 +72,11 @@ static void handle_shell_destroy(struct wl_listener *listener, void *data) {
|
|||
struct wlr_xwayland *xwayland =
|
||||
wl_container_of(listener, xwayland, shell_destroy);
|
||||
xwayland->shell_v1 = NULL;
|
||||
wl_list_remove(&xwayland->shell_destroy.link);
|
||||
// Will remove this list in handle_shell_destroy().
|
||||
// This ensures the link is always initialized and
|
||||
// avoids the need to keep check conditions in sync.
|
||||
wl_list_init(&xwayland->shell_destroy.link);
|
||||
}
|
||||
|
||||
void wlr_xwayland_destroy(struct wlr_xwayland *xwayland) {
|
||||
|
|
|
|||
|
|
@ -2530,6 +2530,7 @@ void xwm_set_cursor(struct wlr_xwm *xwm, const uint8_t *pixels, uint32_t stride,
|
|||
struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {
|
||||
struct wlr_xwm *xwm = calloc(1, sizeof(*xwm));
|
||||
if (xwm == NULL) {
|
||||
close(wm_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -2544,11 +2545,13 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {
|
|||
|
||||
xwm->ping_timeout = 10000;
|
||||
|
||||
// xcb_connect_to_fd takes ownership of the FD regardless of success/failure
|
||||
xwm->xcb_conn = xcb_connect_to_fd(wm_fd, NULL);
|
||||
|
||||
int rc = xcb_connection_has_error(xwm->xcb_conn);
|
||||
if (rc) {
|
||||
wlr_log(WLR_ERROR, "xcb connect failed: %d", rc);
|
||||
xcb_disconnect(xwm->xcb_conn);
|
||||
free(xwm);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue