Merge branch 'single-pixel-optimize' into 'master'

Draft: wlr_renderer: Add single pixel optimization

See merge request wlroots/wlroots!3650
This commit is contained in:
Alexander Orzechowski 2022-08-11 11:28:57 +00:00
commit e3cc1dda94
39 changed files with 1149 additions and 972 deletions

View file

@ -14,6 +14,7 @@
#include <wlr/render/wlr_renderer.h>
#include <wlr/render/wlr_texture.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_raster.h>
#include <wlr/render/dmabuf.h>
struct wlr_box;
@ -27,8 +28,10 @@ struct wlr_renderer_impl {
void (*end)(struct wlr_renderer *renderer);
void (*clear)(struct wlr_renderer *renderer, const float color[static 4]);
void (*scissor)(struct wlr_renderer *renderer, struct wlr_box *box);
bool (*render_subtexture_with_matrix)(struct wlr_renderer *renderer,
struct wlr_texture *texture, const struct wlr_fbox *box,
bool (*raster_upload)(struct wlr_renderer *renderer,
struct wlr_raster *raster);
bool (*render_subraster_with_matrix)(struct wlr_renderer *renderer,
struct wlr_raster *raster, const struct wlr_fbox *box,
const float matrix[static 9], float alpha);
void (*render_quad_with_matrix)(struct wlr_renderer *renderer,
const float color[static 4], const float matrix[static 9]);
@ -46,22 +49,18 @@ struct wlr_renderer_impl {
void (*destroy)(struct wlr_renderer *renderer);
int (*get_drm_fd)(struct wlr_renderer *renderer);
uint32_t (*get_render_buffer_caps)(struct wlr_renderer *renderer);
struct wlr_texture *(*texture_from_buffer)(struct wlr_renderer *renderer,
struct wlr_buffer *buffer);
};
void wlr_renderer_init(struct wlr_renderer *renderer,
const struct wlr_renderer_impl *impl);
struct wlr_texture_impl {
bool (*write_pixels)(struct wlr_texture *texture,
uint32_t stride, uint32_t width, uint32_t height,
uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y,
const void *data);
bool (*update_from_raster)(struct wlr_texture *texture,
struct wlr_raster *raster, pixman_region32_t *damage);
void (*destroy)(struct wlr_texture *texture);
};
void wlr_texture_init(struct wlr_texture *texture,
void wlr_texture_init(struct wlr_texture *texture, struct wlr_renderer *rendener,
const struct wlr_texture_impl *impl, uint32_t width, uint32_t height);
#endif

View file

@ -22,6 +22,5 @@ pixman_image_t *wlr_pixman_renderer_get_current_image(
bool wlr_renderer_is_pixman(struct wlr_renderer *wlr_renderer);
bool wlr_texture_is_pixman(struct wlr_texture *texture);
pixman_image_t *wlr_pixman_texture_get_image(struct wlr_texture *wlr_texture);
#endif

View file

@ -48,22 +48,30 @@ void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]);
* box.
*/
void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box);
/**
* Renders the requested texture.
* The renderer will attempt to upload the raster using an available compatible
* source found in the raster to the device that the renderer is running on.
* If the raster is already uploaded to said device, then this is a no-op.
*/
bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture,
bool wlr_renderer_raster_upload(struct wlr_renderer *r,
struct wlr_raster *raster);
/**
* Renders the requested raster.
*/
bool wlr_render_raster(struct wlr_renderer *r, struct wlr_raster *raster,
const float projection[static 9], int x, int y, float alpha);
/**
* Renders the requested texture using the provided matrix.
* Renders the requested raster using the provided matrix.
*/
bool wlr_render_texture_with_matrix(struct wlr_renderer *r,
struct wlr_texture *texture, const float matrix[static 9], float alpha);
bool wlr_render_raster_with_matrix(struct wlr_renderer *r,
struct wlr_raster *raster, const float matrix[static 9], float alpha);
/**
* Renders the requested texture using the provided matrix, after cropping it
* Renders the requested raster using the provided matrix, after cropping it
* to the provided rectangle.
*/
bool wlr_render_subtexture_with_matrix(struct wlr_renderer *r,
struct wlr_texture *texture, const struct wlr_fbox *box,
bool wlr_render_subraster_with_matrix(struct wlr_renderer *r,
struct wlr_raster *raster, const struct wlr_fbox *box,
const float matrix[static 9], float alpha);
/**
* Renders a solid rectangle in the specified color.

View file

@ -9,51 +9,40 @@
#ifndef WLR_RENDER_WLR_TEXTURE_H
#define WLR_RENDER_WLR_TEXTURE_H
#include <pixman.h>
#include <stdint.h>
#include <wayland-server-core.h>
#include <wlr/render/dmabuf.h>
#include <wlr/types/wlr_raster.h>
struct wlr_buffer;
struct wlr_renderer;
struct wlr_texture_impl;
struct wlr_texture {
const struct wlr_texture_impl *impl;
uint32_t width, height;
struct wlr_renderer *renderer;
struct wlr_raster *raster;
struct wl_list link;
};
/**
* Create a new texture from raw pixel data. `stride` is in bytes. The returned
* texture is mutable.
*/
struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer,
uint32_t fmt, uint32_t stride, uint32_t width, uint32_t height,
const void *data);
/**
* Create a new texture from a DMA-BUF. The returned texture is immutable.
*/
struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer,
struct wlr_dmabuf_attributes *attribs);
/**
* Update a texture with raw pixels. The texture must be mutable, and the input
* data must have the same pixel format that the texture was created with.
* Update a texture with a struct wlr_raster's contents.
*
* The update might be rejected (in case the texture is immutable, the raster
* doesn't have a compatible source, unsupported type/format, etc), so callers
* must be prepared to fall back.
*
* The damage can be used by the renderer as an optimization: only the supplied
* region needs to be updated.
*/
bool wlr_texture_write_pixels(struct wlr_texture *texture,
uint32_t stride, uint32_t width, uint32_t height,
uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y,
const void *data);
bool wlr_texture_update_from_raster(struct wlr_texture *texture,
struct wlr_raster *raster, pixman_region32_t *damage);
/**
* Destroys the texture.
*/
void wlr_texture_destroy(struct wlr_texture *texture);
/**
* Create a new texture from a buffer.
*/
struct wlr_texture *wlr_texture_from_buffer(struct wlr_renderer *renderer,
struct wlr_buffer *buffer);
#endif

View file

@ -132,53 +132,9 @@ bool wlr_buffer_begin_data_ptr_access(struct wlr_buffer *buffer, uint32_t flags,
void **data, uint32_t *format, size_t *stride);
void wlr_buffer_end_data_ptr_access(struct wlr_buffer *buffer);
/**
* A client buffer.
*/
struct wlr_client_buffer {
struct wlr_buffer base;
/**
* The buffer's texture, if any. A buffer will not have a texture if the
* client destroys the buffer before it has been released.
*/
struct wlr_texture *texture;
/**
* The buffer this client buffer was created from. NULL if destroyed.
*/
struct wlr_buffer *source;
// private state
struct wl_listener source_destroy;
// If the client buffer has been created from a wl_shm buffer
uint32_t shm_source_format;
};
/**
* Creates a struct wlr_client_buffer from a given struct wlr_buffer by creating
* a texture from it, and copying its struct wl_resource.
*/
struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer,
struct wlr_renderer *renderer);
/**
* Get a client buffer from a generic buffer. If the buffer isn't a client
* buffer, returns NULL.
*/
struct wlr_client_buffer *wlr_client_buffer_get(struct wlr_buffer *buffer);
/**
* Check if a resource is a wl_buffer resource.
*/
bool wlr_resource_is_buffer(struct wl_resource *resource);
/**
* Try to update the buffer's content.
*
* Fails if there's more than one reference to the buffer or if the texture
* isn't mutable.
*/
bool wlr_client_buffer_apply_damage(struct wlr_client_buffer *client_buffer,
struct wlr_buffer *next, pixman_region32_t *damage);
#endif

View file

@ -88,18 +88,17 @@ struct wlr_surface_output {
struct wlr_surface {
struct wl_resource *resource;
struct wlr_renderer *renderer;
/**
* The surface's buffer, if any. A surface has an attached buffer when it
* commits with a non-null buffer in its pending state. A surface will not
* have a buffer if it has never committed one, has committed a null buffer,
* or something went wrong with uploading the buffer.
*/
struct wlr_client_buffer *buffer;
/**
* The buffer position, in surface-local units.
*/
int sx, sy;
/**
* The surface's raster, if any. A surface has an attached raster when it
* commits with a non-null buffer in its pending state. A surface will not
* have a raster if it has never committed one or has committed a null
* buffer.
*/
struct wlr_raster *raster;
/**
* The last commit's buffer damage, in buffer-local coordinates. This
* contains both the damage accumulated by the client via
@ -154,8 +153,6 @@ struct wlr_surface {
// private state
struct wl_listener renderer_destroy;
struct {
int32_t scale;
enum wl_output_transform transform;
@ -164,13 +161,13 @@ struct wlr_surface {
} previous;
bool opaque;
};
struct wlr_renderer;
struct wlr_raster *old_raster;
struct wl_listener raster_destroy;
};
struct wlr_compositor {
struct wl_global *global;
struct wlr_renderer *renderer;
struct wl_listener display_destroy;
@ -199,13 +196,6 @@ bool wlr_surface_set_role(struct wlr_surface *surface,
*/
bool wlr_surface_has_buffer(struct wlr_surface *surface);
/**
* Get the texture of the buffer currently attached to this surface. Returns
* NULL if no buffer is currently attached or if something went wrong with
* uploading the buffer.
*/
struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface);
/**
* Get the root of the subsurface tree for this surface. Can return NULL if
* a surface in the tree has been destroyed.
@ -299,7 +289,6 @@ uint32_t wlr_surface_lock_pending(struct wlr_surface *surface);
*/
void wlr_surface_unlock_cached(struct wlr_surface *surface, uint32_t seq);
struct wlr_compositor *wlr_compositor_create(struct wl_display *display,
struct wlr_renderer *renderer);
struct wlr_compositor *wlr_compositor_create(struct wl_display *display);
#endif

View file

@ -34,6 +34,12 @@ struct wlr_dmabuf_v1_buffer {
*/
bool wlr_dmabuf_v1_resource_is_buffer(struct wl_resource *buffer_resource);
/**
* Returns true if the given buffer was created via the linux-dmabuf
* buffer protocol, false otherwise
*/
bool wlr_dmabuf_v1_buffer_is_buffer(struct wlr_buffer *buffer);
/**
* Returns the struct wlr_dmabuf_buffer if the given resource was created
* via the linux-dmabuf buffer protocol.

View file

@ -34,7 +34,7 @@ struct wlr_output_cursor {
struct wl_list link;
// only when using a software cursor without a surface
struct wlr_texture *texture;
struct wlr_raster *raster;
// only when using a cursor surface
struct wlr_surface *surface;
@ -494,8 +494,8 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,
int32_t hotspot_x, int32_t hotspot_y);
void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor,
struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y);
bool wlr_output_cursor_set_buffer(struct wlr_output_cursor *cursor,
struct wlr_buffer *buffer, int32_t hotspot_x, int32_t hotspot_y);
bool wlr_output_cursor_set_raster(struct wlr_output_cursor *cursor,
struct wlr_raster *raster, int32_t hotspot_x, int32_t hotspot_y);
bool wlr_output_cursor_move(struct wlr_output_cursor *cursor,
double x, double y);
void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor);

View file

@ -0,0 +1,84 @@
/*
* 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_RASTER_H
#define WLR_TYPES_WLR_RASTER_H
#include <stdbool.h>
#include <stdlib.h>
#include <wayland-server-core.h>
struct wlr_buffer;
struct wlr_texture;
struct wlr_raster {
// May be NULL
struct wlr_buffer *buffer;
uint32_t width, height;
struct wl_list sources; // struct wlr_texture
struct {
struct wl_signal destroy;
} events;
// private state
size_t n_locks;
};
/**
* Creates a new wlr_raster being backed by the given buffer.
* The creation funciton is referenced: once the creator is done with the raster,
* wlr_raster_unlock must be called.
*/
struct wlr_raster *wlr_raster_create(struct wlr_buffer *buffer);
/**
* Removes and unlocks the buffer assolated with this raster. A raster must be
* created with a buffer so that there is a source of information for textures
* to be created from it, but once there is a texture, that can be used
* as the source of truth and so the buffer can be removed early for other
* purposes.
*/
void wlr_raster_remove_buffer(struct wlr_raster *raster);
/**
* Lock the raster for use. As long as the raster has at least one lock, it
* will not be destroyed. The raster will be created with a reference count at 1
* meaning that whatever produced the raster, must call this funciton.
*/
struct wlr_raster *wlr_raster_lock(struct wlr_raster *raster);
/**
* Unlock the raster. This must be called after wlr_raster_lock once the raster
* has been finished being used.
*/
void wlr_raster_unlock(struct wlr_raster *raster);
/**
* Attaches a wlr_texture to the raster. Consumers of the raster can use the
* given texture for their rendering if needed. The pixel contents of the texture
* must be the same as the source buffer and other textures in the raster.
*/
void wlr_raster_attach(struct wlr_raster *raster, struct wlr_texture *texture);
/**
* Detaches a wlr_texture from the raster. Once the texture is detached, ownership
* of the texture is given to the caller such that the caller may mutate the
* raster if it wishes.
*/
void wlr_raster_detach(struct wlr_raster *raster, struct wlr_texture *texture);
/**
* Create a new raster from raw pixel data. `stride` is in bytes.
*/
struct wlr_raster *wlr_raster_from_pixels(uint32_t fmt, uint32_t stride,
uint32_t width, uint32_t height, const void *data);
#endif

View file

@ -23,6 +23,7 @@
#include <wayland-server-core.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_damage_ring.h>
#include <wlr/types/wlr_raster.h>
struct wlr_output;
struct wlr_output_layout;
@ -30,21 +31,21 @@ struct wlr_xdg_surface;
struct wlr_layer_surface_v1;
struct wlr_scene_node;
struct wlr_scene_buffer;
struct wlr_scene_raster;
typedef void (*wlr_scene_node_iterator_func_t)(struct wlr_scene_node *node,
int sx, int sy, void *data);
typedef bool (*wlr_scene_buffer_point_accepts_input_func_t)(
struct wlr_scene_buffer *buffer, int sx, int sy);
typedef bool (*wlr_scene_raster_point_accepts_input_func_t)(
struct wlr_scene_raster *raster, int sx, int sy);
typedef void (*wlr_scene_buffer_iterator_func_t)(
struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data);
typedef void (*wlr_scene_raster_iterator_func_t)(
struct wlr_scene_raster *raster, int sx, int sy, void *user_data);
enum wlr_scene_node_type {
WLR_SCENE_NODE_TREE,
WLR_SCENE_NODE_RECT,
WLR_SCENE_NODE_BUFFER,
WLR_SCENE_NODE_RASTER,
};
/** A node is an object in the scene. */
@ -98,7 +99,7 @@ struct wlr_scene {
/** A scene-graph node displaying a single surface. */
struct wlr_scene_surface {
struct wlr_scene_buffer *buffer;
struct wlr_scene_raster *raster;
struct wlr_surface *surface;
// private state
@ -120,12 +121,12 @@ struct wlr_scene_rect {
float color[4];
};
/** A scene-graph node displaying a buffer */
struct wlr_scene_buffer {
/** A scene-graph node displaying a raster */
struct wlr_scene_raster {
struct wlr_scene_node node;
// May be NULL
struct wlr_buffer *buffer;
struct wlr_raster *raster;
struct {
struct wl_signal output_enter; // struct wlr_scene_output
@ -135,11 +136,11 @@ struct wlr_scene_buffer {
} events;
// May be NULL
wlr_scene_buffer_point_accepts_input_func_t point_accepts_input;
wlr_scene_raster_point_accepts_input_func_t point_accepts_input;
/**
* The output that the largest area of this buffer is displayed on.
* This may be NULL if the buffer is not currently displayed on any
* The output that the largest area of this raster is displayed on.
* This may be NULL if the raster is not currently displayed on any
* outputs. This is the output that should be used for frame callbacks,
* presentation feedback, etc.
*/
@ -148,7 +149,6 @@ struct wlr_scene_buffer {
// private state
uint64_t active_outputs;
struct wlr_texture *texture;
struct wlr_fbox src_box;
int dst_width, dst_height;
enum wl_output_transform transform;
@ -240,12 +240,12 @@ void wlr_scene_node_reparent(struct wlr_scene_node *node,
*/
bool wlr_scene_node_coords(struct wlr_scene_node *node, int *lx, int *ly);
/**
* Call `iterator` on each buffer in the scene-graph, with the buffer's
* Call `iterator` on each raster in the scene-graph, with the raster's
* position in layout coordinates. The function is called from root to leaves
* (in rendering order).
*/
void wlr_scene_node_for_each_buffer(struct wlr_scene_node *node,
wlr_scene_buffer_iterator_func_t iterator, void *user_data);
void wlr_scene_node_for_each_raster(struct wlr_scene_node *node,
wlr_scene_raster_iterator_func_t iterator, void *user_data);
/**
* Find the topmost node in this scene-graph that contains the point at the
* given layout-local coordinates. (For surface nodes, this means accepting
@ -285,14 +285,14 @@ struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent);
struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_tree *parent,
struct wlr_surface *surface);
struct wlr_scene_buffer *wlr_scene_buffer_from_node(struct wlr_scene_node *node);
struct wlr_scene_raster *wlr_scene_raster_from_node(struct wlr_scene_node *node);
/**
* If this buffer is backed by a surface, then the struct wlr_scene_surface is
* If this raster is backed by a surface, then the struct wlr_scene_surface is
* returned. If not, NULL will be returned.
*/
struct wlr_scene_surface *wlr_scene_surface_from_buffer(
struct wlr_scene_buffer *scene_buffer);
struct wlr_scene_surface *wlr_scene_surface_from_raster(
struct wlr_scene_raster *scene_raster);
/**
* Add a node displaying a solid-colored rectangle to the scene-graph.
@ -311,59 +311,59 @@ void wlr_scene_rect_set_size(struct wlr_scene_rect *rect, int width, int height)
void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[static 4]);
/**
* Add a node displaying a buffer to the scene-graph.
* Add a node displaying a raster to the scene-graph.
*
* If the buffer is NULL, this node will not be displayed.
* If the raster is NULL, this node will not be displayed.
*/
struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
struct wlr_buffer *buffer);
struct wlr_scene_raster *wlr_scene_raster_create(struct wlr_scene_tree *parent,
struct wlr_raster *raster);
/**
* Sets the buffer's backing buffer.
* Sets the raster's backing raster.
*
* If the buffer is NULL, the buffer node will not be displayed.
* If the raster is NULL, the raster node will not be displayed.
*/
void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer,
struct wlr_buffer *buffer);
void wlr_scene_raster_set_raster(struct wlr_scene_raster *scene_raster,
struct wlr_raster *raster);
/**
* Sets the buffer's backing buffer with a custom damage region.
* Sets the raster's backing raster with a custom damage region.
*
* The damage region is in buffer-local coordinates. If the region is NULL,
* the whole buffer node will be damaged.
* The damage region is in raster-local coordinates. If the region is NULL,
* the whole raster node will be damaged.
*/
void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer,
struct wlr_buffer *buffer, pixman_region32_t *region);
void wlr_scene_raster_set_raster_with_damage(struct wlr_scene_raster *scene_raster,
struct wlr_raster *raster, pixman_region32_t *region);
/**
* Set the source rectangle describing the region of the buffer which will be
* sampled to render this node. This allows cropping the buffer.
* Set the source rectangle describing the region of the raster which will be
* sampled to render this node. This allows cropping the raster.
*
* If NULL, the whole buffer is sampled. By default, the source box is NULL.
* If NULL, the whole raster is sampled. By default, the source box is NULL.
*/
void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer,
void wlr_scene_raster_set_source_box(struct wlr_scene_raster *scene_raster,
const struct wlr_fbox *box);
/**
* Set the destination size describing the region of the scene-graph the buffer
* will be painted onto. This allows scaling the buffer.
* Set the destination size describing the region of the scene-graph the raster
* will be painted onto. This allows scaling the raster.
*
* If zero, the destination size will be the buffer size. By default, the
* If zero, the destination size will be the raster size. By default, the
* destination size is zero.
*/
void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer,
void wlr_scene_raster_set_dest_size(struct wlr_scene_raster *scene_raster,
int width, int height);
/**
* Set a transform which will be applied to the buffer.
* Set a transform which will be applied to the raster.
*/
void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer,
void wlr_scene_raster_set_transform(struct wlr_scene_raster *scene_raster,
enum wl_output_transform transform);
/**
* Calls the buffer's frame_done signal.
* Calls the raster's frame_done signal.
*/
void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer,
void wlr_scene_raster_send_frame_done(struct wlr_scene_raster *scene_raster,
struct timespec *now);
/**
@ -394,12 +394,12 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output);
void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output,
struct timespec *now);
/**
* Call `iterator` on each buffer in the scene-graph visible on the output,
* with the buffer's position in layout coordinates. The function is called
* Call `iterator` on each raster in the scene-graph visible on the output,
* with the raster's position in layout coordinates. The function is called
* from root to leaves (in rendering order).
*/
void wlr_scene_output_for_each_buffer(struct wlr_scene_output *scene_output,
wlr_scene_buffer_iterator_func_t iterator, void *user_data);
void wlr_scene_output_for_each_raster(struct wlr_scene_output *scene_output,
wlr_scene_raster_iterator_func_t iterator, void *user_data);
/**
* Get a scene-graph output from a struct wlr_output.
*