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

@ -16,6 +16,7 @@
#include <wlr/backend/interface.h>
#include <wlr/interfaces/wlr_output.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/util/box.h>
#include <wlr/util/log.h>
@ -1491,7 +1492,7 @@ static void handle_page_flip(int fd, unsigned seq,
* interface.
*/
if (!drm->parent && plane->current_fb &&
wlr_client_buffer_get(plane->current_fb->wlr_buf)) {
wlr_dmabuf_v1_buffer_is_buffer(plane->current_fb->wlr_buf)) {
present_flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
}

View file

@ -90,14 +90,14 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
return NULL;
}
struct wlr_texture *tex = wlr_texture_from_buffer(renderer, buffer);
if (tex == NULL) {
struct wlr_raster *raster = wlr_raster_create(buffer);
if (!raster) {
return NULL;
}
struct wlr_buffer *dst = wlr_swapchain_acquire(surf->swapchain, NULL);
if (!dst) {
wlr_texture_destroy(tex);
wlr_raster_unlock(raster);
return NULL;
}
@ -107,16 +107,15 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
if (!wlr_renderer_begin_with_buffer(renderer, dst)) {
wlr_buffer_unlock(dst);
wlr_texture_destroy(tex);
wlr_raster_unlock(raster);
return NULL;
}
wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 0.0 });
wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f);
wlr_render_raster_with_matrix(renderer, raster, mat, 1.0f);
wlr_renderer_end(renderer);
wlr_texture_destroy(tex);
wlr_raster_unlock(raster);
return dst;
}

View file

@ -56,8 +56,8 @@ static void render_surface(struct wlr_surface *surface,
struct render_data *rdata = data;
struct wlr_output *output = rdata->output;
struct wlr_texture *texture = wlr_surface_get_texture(surface);
if (texture == NULL) {
struct wlr_raster *raster = wlr_raster_create(surface->current.buffer);
if (raster == NULL) {
return;
}
@ -74,9 +74,11 @@ static void render_surface(struct wlr_surface *surface,
wlr_matrix_project_box(matrix, &box, transform, 0,
output->transform_matrix);
wlr_render_texture_with_matrix(rdata->renderer, texture, matrix, 1);
wlr_render_raster_with_matrix(rdata->renderer, raster, matrix, 1);
wlr_surface_send_frame_done(surface, rdata->when);
wlr_raster_unlock(raster);
}
static void output_handle_frame(struct wl_listener *listener, void *data) {
@ -211,7 +213,7 @@ int main(int argc, char *argv[]) {
server.allocator = wlr_allocator_autocreate(server.backend,
server.renderer);
wlr_compositor_create(server.wl_display, server.renderer);
wlr_compositor_create(server.wl_display);
server.output_layout = wlr_output_layout_create();

View file

@ -29,7 +29,7 @@ struct sample_state {
struct wl_listener new_input;
struct wlr_renderer *renderer;
struct wlr_allocator *allocator;
struct wlr_texture *cat_texture;
struct wlr_raster *cat_raster;
struct wlr_output_layout *layout;
float x_offs, y_offs;
float x_vel, y_vel;
@ -134,7 +134,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
wlr_output_layout_output_coords(sample->layout, output->output,
&local_x, &local_y);
wlr_render_texture(sample->renderer, sample->cat_texture,
wlr_render_raster(sample->renderer, sample->cat_raster,
wlr_output->transform_matrix, local_x, local_y, 1.0f);
}
@ -279,9 +279,8 @@ int main(int argc, char *argv[]) {
state.new_input.notify = new_input_notify;
state.renderer = wlr_renderer_autocreate(wlr);
state.cat_texture = wlr_texture_from_pixels(state.renderer,
DRM_FORMAT_ABGR8888, cat_tex.width * 4, cat_tex.width, cat_tex.height,
cat_tex.pixel_data);
state.cat_raster = wlr_raster_from_pixels(DRM_FORMAT_ABGR8888,
cat_tex.width * 4, cat_tex.width, cat_tex.height, cat_tex.pixel_data);
state.allocator = wlr_allocator_autocreate(wlr, state.renderer);
@ -292,7 +291,7 @@ int main(int argc, char *argv[]) {
}
wl_display_run(display);
wlr_texture_destroy(state.cat_texture);
wlr_raster_unlock(state.cat_raster);
wl_display_destroy(state.display);
wlr_output_layout_destroy(state.layout);

View file

@ -27,7 +27,7 @@ struct sample_state {
struct timespec last_frame;
struct wlr_renderer *renderer;
struct wlr_allocator *allocator;
struct wlr_texture *cat_texture;
struct wlr_raster *cat_raster;
struct wl_list outputs;
enum wl_output_transform transform;
};
@ -65,7 +65,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
for (int y = -128 + (int)sample_output->y_offs; y < height; y += 128) {
for (int x = -128 + (int)sample_output->x_offs; x < width; x += 128) {
wlr_render_texture(sample->renderer, sample->cat_texture,
wlr_render_raster(sample->renderer, sample->cat_raster,
wlr_output->transform_matrix, x, y, 1.0f);
}
}
@ -256,10 +256,9 @@ int main(int argc, char *argv[]) {
wlr_backend_destroy(wlr);
exit(EXIT_FAILURE);
}
state.cat_texture = wlr_texture_from_pixels(state.renderer,
DRM_FORMAT_ABGR8888, cat_tex.width * 4, cat_tex.width, cat_tex.height,
cat_tex.pixel_data);
if (!state.cat_texture) {
state.cat_raster = wlr_raster_from_pixels(DRM_FORMAT_ABGR8888,
cat_tex.width * 4, cat_tex.width, cat_tex.height, cat_tex.pixel_data);
if (!state.cat_raster) {
wlr_log(WLR_ERROR, "Could not start compositor, OOM");
exit(EXIT_FAILURE);
}
@ -273,6 +272,6 @@ int main(int argc, char *argv[]) {
}
wl_display_run(display);
wlr_texture_destroy(state.cat_texture);
wlr_raster_unlock(state.cat_raster);
wl_display_destroy(display);
}

View file

@ -99,7 +99,7 @@ static void surface_handle_commit(struct wl_listener *listener, void *data) {
static void surface_handle_destroy(struct wl_listener *listener, void *data) {
struct surface *surface = wl_container_of(listener, surface, destroy);
wlr_scene_node_destroy(&surface->scene_surface->buffer->node);
wlr_scene_node_destroy(&surface->scene_surface->raster->node);
wlr_scene_node_destroy(&surface->border->node);
wl_list_remove(&surface->destroy.link);
wl_list_remove(&surface->link);
@ -129,7 +129,7 @@ static void server_handle_new_surface(struct wl_listener *listener,
surface->scene_surface =
wlr_scene_surface_create(&server->scene->tree, wlr_surface);
wlr_scene_node_set_position(&surface->scene_surface->buffer->node,
wlr_scene_node_set_position(&surface->scene_surface->raster->node,
pos + border_width, pos + border_width);
}
@ -166,8 +166,7 @@ int main(int argc, char *argv[]) {
server.allocator = wlr_allocator_autocreate(server.backend,
server.renderer);
struct wlr_compositor *compositor =
wlr_compositor_create(server.display, server.renderer);
struct wlr_compositor *compositor = wlr_compositor_create(server.display);
wlr_xdg_shell_create(server.display, 2);

View file

@ -25,7 +25,7 @@ struct sample_state {
struct wl_display *display;
struct wlr_renderer *renderer;
struct wlr_allocator *allocator;
struct wlr_texture *cat_texture;
struct wlr_raster *cat_raster;
struct wl_list touch_points;
struct timespec last_frame;
struct wl_listener new_output;
@ -81,9 +81,9 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
struct touch_point *p;
wl_list_for_each(p, &sample->touch_points, link) {
int x = (int)(p->x * width) - sample->cat_texture->width / 2;
int y = (int)(p->y * height) - sample->cat_texture->height / 2;
wlr_render_texture(sample->renderer, sample->cat_texture,
int x = (int)(p->x * width) - sample->cat_raster->width / 2;
int y = (int)(p->y * height) - sample->cat_raster->height / 2;
wlr_render_raster(sample->renderer, sample->cat_raster,
wlr_output->transform_matrix, x, y, 1.0f);
}
@ -264,10 +264,9 @@ int main(int argc, char *argv[]) {
wlr_log(WLR_ERROR, "Could not start compositor, OOM");
exit(EXIT_FAILURE);
}
state.cat_texture = wlr_texture_from_pixels(state.renderer,
DRM_FORMAT_ARGB8888, cat_tex.width * 4, cat_tex.width, cat_tex.height,
cat_tex.pixel_data);
if (!state.cat_texture) {
state.cat_raster = wlr_raster_from_pixels(DRM_FORMAT_ARGB8888,
cat_tex.width * 4, cat_tex.width, cat_tex.height, cat_tex.pixel_data);
if (!state.cat_raster) {
wlr_log(WLR_ERROR, "Could not start compositor, OOM");
exit(EXIT_FAILURE);
}
@ -281,6 +280,6 @@ int main(int argc, char *argv[]) {
}
wl_display_run(display);
wlr_texture_destroy(state.cat_texture);
wlr_raster_unlock(state.cat_raster);
wl_display_destroy(display);
}

View file

@ -92,7 +92,6 @@ struct wlr_gles2_buffer {
struct wlr_gles2_texture {
struct wlr_texture wlr_texture;
struct wlr_gles2_renderer *renderer;
struct wl_list link; // wlr_gles2_renderer.textures
// Basically:
@ -123,13 +122,11 @@ const uint32_t *get_gles2_shm_formats(const struct wlr_gles2_renderer *renderer,
struct wlr_gles2_renderer *gles2_get_renderer(
struct wlr_renderer *wlr_renderer);
struct wlr_gles2_texture *gles2_get_texture(
struct wlr_texture *wlr_texture);
struct wlr_gles2_texture *gles2_raster_upload(struct wlr_gles2_renderer *renderer,
struct wlr_raster *wlr_raster);
struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer,
struct wl_resource *data);
struct wlr_texture *gles2_texture_from_buffer(struct wlr_renderer *wlr_renderer,
struct wlr_buffer *buffer);
void gles2_texture_destroy(struct wlr_gles2_texture *texture);
void push_gles2_debug_(struct wlr_gles2_renderer *renderer,

View file

@ -37,7 +37,6 @@ struct wlr_pixman_buffer {
struct wlr_pixman_texture {
struct wlr_texture wlr_texture;
struct wlr_pixman_renderer *renderer;
struct wl_list link; // wlr_pixman_renderer.textures
pixman_image_t *image;

View file

@ -234,7 +234,6 @@ struct wlr_vk_renderer *vulkan_get_renderer(struct wlr_renderer *r);
// State (e.g. image texture) associated with a surface.
struct wlr_vk_texture {
struct wlr_texture wlr_texture;
struct wlr_vk_renderer *renderer;
uint32_t mem_count;
VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
VkImage image;
@ -255,13 +254,12 @@ struct wlr_vk_texture {
struct wl_listener buffer_destroy;
};
struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture);
struct wlr_vk_texture *vulkan_raster_upload(struct wlr_vk_renderer *renderer,
struct wlr_raster *wlr_raster);
VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer,
const struct wlr_dmabuf_attributes *attribs,
VkDeviceMemory mems[static WLR_DMABUF_MAX_PLANES], uint32_t *n_mems,
bool for_render);
struct wlr_texture *vulkan_texture_from_buffer(
struct wlr_renderer *wlr_renderer, struct wlr_buffer *buffer);
void vulkan_texture_destroy(struct wlr_vk_texture *texture);
struct wlr_vk_descriptor_pool {

View file

@ -22,6 +22,9 @@ struct wlr_shm_client_buffer {
struct wl_listener release;
};
bool buffer_is_shm_client_buffer(struct wlr_buffer *buffer);
struct wlr_shm_client_buffer *shm_client_buffer_from_buffer(struct wlr_buffer *buffer);
/**
* A read-only buffer that holds a data pointer.
*

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.
*

View file

@ -246,15 +246,17 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer,
pop_gles2_debug(renderer);
}
static bool gles2_render_subtexture_with_matrix(
struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture,
static bool gles2_render_subraster_with_matrix(
struct wlr_renderer *wlr_renderer, struct wlr_raster *wlr_raster,
const struct wlr_fbox *box, const float matrix[static 9],
float alpha) {
struct wlr_gles2_renderer *renderer =
gles2_get_renderer_in_context(wlr_renderer);
struct wlr_gles2_texture *texture =
gles2_get_texture(wlr_texture);
assert(texture->renderer == renderer);
gles2_raster_upload(renderer, wlr_raster);
if (!texture) {
return false;
}
struct wlr_gles2_tex_shader *shader = NULL;
@ -305,10 +307,10 @@ static bool gles2_render_subtexture_with_matrix(
glUniform1i(shader->tex, 0);
glUniform1f(shader->alpha, alpha);
const GLfloat x1 = box->x / wlr_texture->width;
const GLfloat y1 = box->y / wlr_texture->height;
const GLfloat x2 = (box->x + box->width) / wlr_texture->width;
const GLfloat y2 = (box->y + box->height) / wlr_texture->height;
const GLfloat x1 = box->x / wlr_raster->width;
const GLfloat y1 = box->y / wlr_raster->height;
const GLfloat x2 = (box->x + box->width) / wlr_raster->width;
const GLfloat y2 = (box->y + box->height) / wlr_raster->height;
const GLfloat texcoord[] = {
x2, y1, // top right
x1, y1, // top left
@ -529,6 +531,13 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) {
free(renderer);
}
static bool _gles2_raster_upload(struct wlr_renderer *wlr_renderer,
struct wlr_raster *raster) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
struct wlr_gles2_texture *texture = gles2_raster_upload(renderer, raster);
return texture;
}
static const struct wlr_renderer_impl renderer_impl = {
.destroy = gles2_destroy,
.bind_buffer = gles2_bind_buffer,
@ -536,7 +545,8 @@ static const struct wlr_renderer_impl renderer_impl = {
.end = gles2_end,
.clear = gles2_clear,
.scissor = gles2_scissor,
.render_subtexture_with_matrix = gles2_render_subtexture_with_matrix,
.raster_upload = _gles2_raster_upload,
.render_subraster_with_matrix = gles2_render_subraster_with_matrix,
.render_quad_with_matrix = gles2_render_quad_with_matrix,
.get_shm_texture_formats = gles2_get_shm_texture_formats,
.get_dmabuf_texture_formats = gles2_get_dmabuf_texture_formats,
@ -545,7 +555,6 @@ static const struct wlr_renderer_impl renderer_impl = {
.read_pixels = gles2_read_pixels,
.get_drm_fd = gles2_get_drm_fd,
.get_render_buffer_caps = gles2_get_render_buffer_caps,
.texture_from_buffer = gles2_texture_from_buffer,
};
void push_gles2_debug_(struct wlr_gles2_renderer *renderer,

View file

@ -23,7 +23,7 @@ bool wlr_texture_is_gles2(struct wlr_texture *wlr_texture) {
return wlr_texture->impl == &texture_impl;
}
struct wlr_gles2_texture *gles2_get_texture(
static struct wlr_gles2_texture *gles2_get_texture(
struct wlr_texture *wlr_texture) {
assert(wlr_texture_is_gles2(wlr_texture));
return (struct wlr_gles2_texture *)wlr_texture;
@ -44,14 +44,25 @@ static bool check_stride(const struct wlr_pixel_format_info *fmt,
return true;
}
static bool gles2_texture_write_pixels(struct wlr_texture *wlr_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) {
static bool gles2_texture_update_from_raster(struct wlr_texture *wlr_texture,
struct wlr_raster *raster, pixman_region32_t *damage) {
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
struct wlr_buffer *buffer = raster->buffer;
if (texture->target != GL_TEXTURE_2D || texture->image != EGL_NO_IMAGE_KHR) {
wlr_log(WLR_ERROR, "Cannot write pixels to immutable texture");
return false;
}
void *data;
uint32_t format;
size_t stride;
if (!wlr_buffer_begin_data_ptr_access(buffer,
WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) {
return false;
}
if (format != texture->drm_format) {
wlr_buffer_end_data_ptr_access(buffer);
return false;
}
@ -63,24 +74,37 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
drm_get_pixel_format_info(texture->drm_format);
assert(drm_fmt);
if (!check_stride(drm_fmt, stride, width)) {
if (!check_stride(drm_fmt, stride, buffer->width)) {
wlr_buffer_end_data_ptr_access(buffer);
return false;
}
struct wlr_gles2_renderer *renderer =
gles2_get_renderer(texture->wlr_texture.renderer);
struct wlr_egl_context prev_ctx;
wlr_egl_save_context(&prev_ctx);
wlr_egl_make_current(texture->renderer->egl);
wlr_egl_make_current(renderer->egl);
push_gles2_debug(texture->renderer);
push_gles2_debug(renderer);
glBindTexture(GL_TEXTURE_2D, texture->tex);
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (drm_fmt->bpp / 8));
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, src_x);
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, src_y);
int rects_len = 0;
pixman_box32_t *rects = pixman_region32_rectangles(damage, &rects_len);
glTexSubImage2D(GL_TEXTURE_2D, 0, dst_x, dst_y, width, height,
fmt->gl_format, fmt->gl_type, data);
for (int i = 0; i < rects_len; i++) {
pixman_box32_t rect = rects[i];
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (drm_fmt->bpp / 8));
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, rect.x1);
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, rect.y1);
int width = rect.x2 - rect.x1;
int height = rect.y2 - rect.y1;
glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x1, rect.y1, width, height,
fmt->gl_format, fmt->gl_type, data);
}
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
@ -88,10 +112,12 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
glBindTexture(GL_TEXTURE_2D, 0);
pop_gles2_debug(texture->renderer);
pop_gles2_debug(renderer);
wlr_egl_restore_context(&prev_ctx);
wlr_buffer_end_data_ptr_access(buffer);
return true;
}
@ -104,18 +130,21 @@ static bool gles2_texture_invalidate(struct wlr_gles2_texture *texture) {
return true;
}
struct wlr_gles2_renderer *renderer =
gles2_get_renderer(texture->wlr_texture.renderer);
struct wlr_egl_context prev_ctx;
wlr_egl_save_context(&prev_ctx);
wlr_egl_make_current(texture->renderer->egl);
wlr_egl_make_current(renderer->egl);
push_gles2_debug(texture->renderer);
push_gles2_debug(renderer);
glBindTexture(texture->target, texture->tex);
texture->renderer->procs.glEGLImageTargetTexture2DOES(texture->target,
renderer->procs.glEGLImageTargetTexture2DOES(texture->target,
texture->image);
glBindTexture(texture->target, 0);
pop_gles2_debug(texture->renderer);
pop_gles2_debug(renderer);
wlr_egl_restore_context(&prev_ctx);
@ -128,16 +157,20 @@ void gles2_texture_destroy(struct wlr_gles2_texture *texture) {
wlr_addon_finish(&texture->buffer_addon);
}
struct wlr_gles2_renderer *renderer =
gles2_get_renderer(texture->wlr_texture.renderer);
struct wlr_egl_context prev_ctx;
wlr_egl_save_context(&prev_ctx);
wlr_egl_make_current(texture->renderer->egl);
wlr_egl_make_current(renderer->egl);
push_gles2_debug(texture->renderer);
push_gles2_debug(renderer);
glDeleteTextures(1, &texture->tex);
wlr_egl_destroy_image(texture->renderer->egl, texture->image);
wlr_egl_destroy_image(renderer->egl, texture->image);
pop_gles2_debug(texture->renderer);
pop_gles2_debug(renderer);
wlr_egl_restore_context(&prev_ctx);
@ -156,7 +189,7 @@ static void gles2_texture_unref(struct wlr_texture *wlr_texture) {
}
static const struct wlr_texture_impl texture_impl = {
.write_pixels = gles2_texture_write_pixels,
.update_from_raster = gles2_texture_update_from_raster,
.destroy = gles2_texture_unref,
};
@ -168,18 +201,16 @@ static struct wlr_gles2_texture *gles2_texture_create(
wlr_log_errno(WLR_ERROR, "Allocation failed");
return NULL;
}
wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height);
texture->renderer = renderer;
wlr_texture_init(&texture->wlr_texture, &renderer->wlr_renderer,
&texture_impl, width, height);
wl_list_insert(&renderer->textures, &texture->link);
return texture;
}
static struct wlr_texture *gles2_texture_from_pixels(
struct wlr_renderer *wlr_renderer,
static struct wlr_gles2_texture *gles2_texture_from_pixels(
struct wlr_gles2_renderer *renderer,
uint32_t drm_format, uint32_t stride, uint32_t width,
uint32_t height, const void *data) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
const struct wlr_gles2_pixel_format *fmt =
get_gles2_format_from_drm(drm_format);
if (fmt == NULL) {
@ -231,7 +262,7 @@ static struct wlr_texture *gles2_texture_from_pixels(
wlr_egl_restore_context(&prev_ctx);
return &texture->wlr_texture;
return texture;
}
static struct wlr_texture *gles2_texture_from_dmabuf(
@ -303,7 +334,7 @@ static const struct wlr_addon_interface texture_addon_impl = {
.destroy = texture_handle_buffer_destroy,
};
static struct wlr_texture *gles2_texture_from_dmabuf_buffer(
static struct wlr_gles2_texture *gles2_texture_from_dmabuf_buffer(
struct wlr_gles2_renderer *renderer, struct wlr_buffer *buffer,
struct wlr_dmabuf_attributes *dmabuf) {
struct wlr_addon *addon =
@ -313,16 +344,16 @@ static struct wlr_texture *gles2_texture_from_dmabuf_buffer(
wl_container_of(addon, texture, buffer_addon);
if (!gles2_texture_invalidate(texture)) {
wlr_log(WLR_ERROR, "Failed to invalidate texture");
return false;
return NULL;
}
wlr_buffer_lock(texture->buffer);
return &texture->wlr_texture;
return texture;
}
struct wlr_texture *wlr_texture =
gles2_texture_from_dmabuf(&renderer->wlr_renderer, dmabuf);
if (wlr_texture == NULL) {
return false;
return NULL;
}
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
@ -330,28 +361,50 @@ static struct wlr_texture *gles2_texture_from_dmabuf_buffer(
wlr_addon_init(&texture->buffer_addon, &buffer->addons,
renderer, &texture_addon_impl);
return &texture->wlr_texture;
return texture;
}
struct wlr_texture *gles2_texture_from_buffer(struct wlr_renderer *wlr_renderer,
struct wlr_buffer *buffer) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
struct wlr_gles2_texture *gles2_raster_upload(struct wlr_gles2_renderer *renderer,
struct wlr_raster *wlr_raster) {
struct wlr_texture *raster_texture;
wl_list_for_each(raster_texture, &wlr_raster->sources, link) {
if (wlr_texture_is_gles2(raster_texture)) {
struct wlr_gles2_texture *gles2_tex =
(struct wlr_gles2_texture *)raster_texture;
if (gles2_tex->wlr_texture.renderer != &renderer->wlr_renderer) {
continue;
}
return gles2_tex;
}
}
struct wlr_buffer *buffer = wlr_raster->buffer;
if (!wlr_raster->buffer) {
// we could possibly do a blit with another texture from another renderer,
// but this is unsupported currently.
return NULL;
}
struct wlr_gles2_texture *texture = NULL;
void *data;
uint32_t format;
size_t stride;
struct wlr_dmabuf_attributes dmabuf;
if (wlr_buffer_get_dmabuf(buffer, &dmabuf)) {
return gles2_texture_from_dmabuf_buffer(renderer, buffer, &dmabuf);
texture = gles2_texture_from_dmabuf_buffer(renderer, buffer, &dmabuf);
} else if (wlr_buffer_begin_data_ptr_access(buffer,
WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) {
struct wlr_texture *tex = gles2_texture_from_pixels(wlr_renderer,
texture = gles2_texture_from_pixels(renderer,
format, stride, buffer->width, buffer->height, data);
wlr_buffer_end_data_ptr_access(buffer);
return tex;
} else {
return NULL;
}
if (texture) {
wlr_raster_attach(wlr_raster, &texture->wlr_texture);
}
return texture;
}
void wlr_gles2_texture_get_attribs(struct wlr_texture *wlr_texture,

View file

@ -40,14 +40,92 @@ bool wlr_texture_is_pixman(struct wlr_texture *texture) {
return texture->impl == &texture_impl;
}
static struct wlr_pixman_texture *get_texture(
struct wlr_texture *wlr_texture) {
assert(wlr_texture_is_pixman(wlr_texture));
return (struct wlr_pixman_texture *)wlr_texture;
static struct wlr_pixman_texture *pixman_texture_create(
struct wlr_pixman_renderer *renderer, uint32_t drm_format,
uint32_t width, uint32_t height) {
struct wlr_pixman_texture *texture =
calloc(1, sizeof(struct wlr_pixman_texture));
if (texture == NULL) {
wlr_log_errno(WLR_ERROR, "Failed to allocate pixman texture");
return NULL;
}
wlr_texture_init(&texture->wlr_texture, &renderer->wlr_renderer,
&texture_impl, width, height);
texture->format_info = drm_get_pixel_format_info(drm_format);
if (!texture->format_info) {
wlr_log(WLR_ERROR, "Unsupported drm format 0x%"PRIX32, drm_format);
free(texture);
return NULL;
}
texture->format = get_pixman_format_from_drm(drm_format);
if (texture->format == 0) {
wlr_log(WLR_ERROR, "Unsupported pixman drm format 0x%"PRIX32,
drm_format);
free(texture);
return NULL;
}
wl_list_insert(&renderer->textures, &texture->link);
return texture;
}
static struct wlr_pixman_texture *raster_upload(
struct wlr_pixman_renderer *renderer, struct wlr_raster *wlr_raster) {
struct wlr_texture *raster_texture;
wl_list_for_each(raster_texture, &wlr_raster->sources, link) {
if (wlr_texture_is_pixman(raster_texture)) {
struct wlr_pixman_texture *pixman_tex =
(struct wlr_pixman_texture *)raster_texture;
if (pixman_tex->wlr_texture.renderer != &renderer->wlr_renderer) {
continue;
}
return pixman_tex;
}
}
struct wlr_buffer *buffer = wlr_raster->buffer;
if (!buffer) {
// we could possibly do a blit with another texture from another renderer,
// but this is unsupported currently.
return NULL;
}
void *data = NULL;
uint32_t drm_format;
size_t stride;
if (!wlr_buffer_begin_data_ptr_access(buffer,
WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &drm_format, &stride)) {
return NULL;
}
wlr_buffer_end_data_ptr_access(buffer);
struct wlr_pixman_texture *texture = pixman_texture_create(renderer,
drm_format, buffer->width, buffer->height);
if (texture == NULL) {
return NULL;
}
texture->image = pixman_image_create_bits_no_clear(texture->format,
buffer->width, buffer->height, data, stride);
if (!texture->image) {
wlr_log(WLR_ERROR, "Failed to create pixman image");
wl_list_remove(&texture->link);
free(texture);
return NULL;
}
texture->buffer = wlr_buffer_lock(buffer);
wlr_raster_attach(wlr_raster, &texture->wlr_texture);
return texture;
}
static void texture_destroy(struct wlr_texture *wlr_texture) {
struct wlr_pixman_texture *texture = get_texture(wlr_texture);
struct wlr_pixman_texture *texture = (struct wlr_pixman_texture *)wlr_texture;
wl_list_remove(&texture->link);
pixman_image_unref(texture->image);
wlr_buffer_unlock(texture->buffer);
@ -215,13 +293,16 @@ static void matrix_to_pixman_transform(struct pixman_transform *transform,
pixman_transform_from_pixman_f_transform(transform, &ftr);
}
static bool pixman_render_subtexture_with_matrix(
struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture,
static bool pixman_render_subraster_with_matrix(
struct wlr_renderer *wlr_renderer, struct wlr_raster *wlr_raster,
const struct wlr_fbox *fbox, const float matrix[static 9],
float alpha) {
struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer);
struct wlr_pixman_texture *texture = get_texture(wlr_texture);
struct wlr_pixman_buffer *buffer = renderer->current_buffer;
struct wlr_pixman_texture *texture = raster_upload(renderer, wlr_raster);
if (!texture){
return false;
}
if (texture->buffer != NULL) {
void *data;
@ -334,72 +415,6 @@ static const struct wlr_drm_format_set *pixman_get_render_formats(
return &renderer->drm_formats;
}
static struct wlr_pixman_texture *pixman_texture_create(
struct wlr_pixman_renderer *renderer, uint32_t drm_format,
uint32_t width, uint32_t height) {
struct wlr_pixman_texture *texture =
calloc(1, sizeof(struct wlr_pixman_texture));
if (texture == NULL) {
wlr_log_errno(WLR_ERROR, "Failed to allocate pixman texture");
return NULL;
}
wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height);
texture->renderer = renderer;
texture->format_info = drm_get_pixel_format_info(drm_format);
if (!texture->format_info) {
wlr_log(WLR_ERROR, "Unsupported drm format 0x%"PRIX32, drm_format);
free(texture);
return NULL;
}
texture->format = get_pixman_format_from_drm(drm_format);
if (texture->format == 0) {
wlr_log(WLR_ERROR, "Unsupported pixman drm format 0x%"PRIX32,
drm_format);
free(texture);
return NULL;
}
wl_list_insert(&renderer->textures, &texture->link);
return texture;
}
static struct wlr_texture *pixman_texture_from_buffer(
struct wlr_renderer *wlr_renderer, struct wlr_buffer *buffer) {
struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer);
void *data = NULL;
uint32_t drm_format;
size_t stride;
if (!wlr_buffer_begin_data_ptr_access(buffer, WLR_BUFFER_DATA_PTR_ACCESS_READ,
&data, &drm_format, &stride)) {
return NULL;
}
wlr_buffer_end_data_ptr_access(buffer);
struct wlr_pixman_texture *texture = pixman_texture_create(renderer,
drm_format, buffer->width, buffer->height);
if (texture == NULL) {
return NULL;
}
texture->image = pixman_image_create_bits_no_clear(texture->format,
buffer->width, buffer->height, data, stride);
if (!texture->image) {
wlr_log(WLR_ERROR, "Failed to create pixman image");
wl_list_remove(&texture->link);
free(texture);
return NULL;
}
texture->buffer = wlr_buffer_lock(buffer);
return &texture->wlr_texture;
}
static bool pixman_bind_buffer(struct wlr_renderer *wlr_renderer,
struct wlr_buffer *wlr_buffer) {
struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer);
@ -488,16 +503,23 @@ static uint32_t pixman_get_render_buffer_caps(struct wlr_renderer *renderer) {
return WLR_BUFFER_CAP_DATA_PTR;
}
static bool pixman_raster_upload(struct wlr_renderer *wlr_renderer,
struct wlr_raster *raster) {
struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer);
struct wlr_pixman_texture *texture = raster_upload(renderer, raster);
return texture;
}
static const struct wlr_renderer_impl renderer_impl = {
.begin = pixman_begin,
.end = pixman_end,
.clear = pixman_clear,
.scissor = pixman_scissor,
.render_subtexture_with_matrix = pixman_render_subtexture_with_matrix,
.raster_upload = pixman_raster_upload,
.render_subraster_with_matrix = pixman_render_subraster_with_matrix,
.render_quad_with_matrix = pixman_render_quad_with_matrix,
.get_shm_texture_formats = pixman_get_shm_texture_formats,
.get_render_formats = pixman_get_render_formats,
.texture_from_buffer = pixman_texture_from_buffer,
.bind_buffer = pixman_bind_buffer,
.destroy = pixman_destroy,
.preferred_read_format = pixman_preferred_read_format,
@ -528,11 +550,6 @@ struct wlr_renderer *wlr_pixman_renderer_create(void) {
return &renderer->wlr_renderer;
}
pixman_image_t *wlr_pixman_texture_get_image(struct wlr_texture *wlr_texture) {
struct wlr_pixman_texture *texture = get_texture(wlr_texture);
return texture->image;
}
pixman_image_t *wlr_pixman_renderer_get_current_image(
struct wlr_renderer *wlr_renderer) {
struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer);

View file

@ -740,14 +740,17 @@ static void vulkan_end(struct wlr_renderer *wlr_renderer) {
}
}
static bool vulkan_render_subtexture_with_matrix(struct wlr_renderer *wlr_renderer,
struct wlr_texture *wlr_texture, const struct wlr_fbox *box,
static bool vulkan_render_subraster_with_matrix(struct wlr_renderer *wlr_renderer,
struct wlr_raster *wlr_raster, const struct wlr_fbox *box,
const float matrix[static 9], float alpha) {
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
VkCommandBuffer cb = renderer->cb;
struct wlr_vk_texture *texture = vulkan_get_texture(wlr_texture);
assert(texture->renderer == renderer);
struct wlr_vk_texture *texture = vulkan_raster_upload(renderer, wlr_raster);
if (!texture) {
return false;
}
if (texture->dmabuf_imported && !texture->owned) {
// Store this texture in the list of textures that need to be
// acquired before rendering and released after rendering.
@ -776,10 +779,10 @@ static bool vulkan_render_subtexture_with_matrix(struct wlr_renderer *wlr_render
struct vert_pcr_data vert_pcr_data;
mat3_to_mat4(final_matrix, vert_pcr_data.mat4);
vert_pcr_data.uv_off[0] = box->x / wlr_texture->width;
vert_pcr_data.uv_off[1] = box->y / wlr_texture->height;
vert_pcr_data.uv_size[0] = box->width / wlr_texture->width;
vert_pcr_data.uv_size[1] = box->height / wlr_texture->height;
vert_pcr_data.uv_off[0] = box->x / wlr_raster->width;
vert_pcr_data.uv_off[1] = box->y / wlr_raster->height;
vert_pcr_data.uv_size[0] = box->width / wlr_raster->width;
vert_pcr_data.uv_size[1] = box->height / wlr_raster->height;
vkCmdPushConstants(cb, renderer->pipe_layout,
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data);
@ -976,13 +979,21 @@ static uint32_t vulkan_get_render_buffer_caps(struct wlr_renderer *wlr_renderer)
return WLR_BUFFER_CAP_DMABUF;
}
static bool _vulkan_raster_upload(struct wlr_renderer *wlr_renderer,
struct wlr_raster *raster) {
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
struct wlr_vk_texture *texture = vulkan_raster_upload(renderer, raster);
return texture;
}
static const struct wlr_renderer_impl renderer_impl = {
.bind_buffer = vulkan_bind_buffer,
.begin = vulkan_begin,
.end = vulkan_end,
.clear = vulkan_clear,
.scissor = vulkan_scissor,
.render_subtexture_with_matrix = vulkan_render_subtexture_with_matrix,
.raster_upload = _vulkan_raster_upload,
.render_subraster_with_matrix = vulkan_render_subraster_with_matrix,
.render_quad_with_matrix = vulkan_render_quad_with_matrix,
.get_shm_texture_formats = vulkan_get_shm_texture_formats,
.get_dmabuf_texture_formats = vulkan_get_dmabuf_texture_formats,
@ -992,7 +1003,6 @@ static const struct wlr_renderer_impl renderer_impl = {
.destroy = vulkan_destroy,
.get_drm_fd = vulkan_get_drm_fd,
.get_render_buffer_caps = vulkan_get_render_buffer_caps,
.texture_from_buffer = vulkan_texture_from_buffer,
};
// Initializes the VkDescriptorSetLayout and VkPipelineLayout needed

View file

@ -18,7 +18,7 @@ bool wlr_texture_is_vk(struct wlr_texture *wlr_texture) {
return wlr_texture->impl == &texture_impl;
}
struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture) {
static struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture) {
assert(wlr_texture_is_vk(wlr_texture));
return (struct wlr_vk_texture *)wlr_texture;
}
@ -42,8 +42,9 @@ static bool write_pixels(struct wlr_texture *wlr_texture,
VkAccessFlags src_access) {
VkResult res;
struct wlr_vk_texture *texture = vulkan_get_texture(wlr_texture);
struct wlr_vk_renderer *renderer = texture->renderer;
VkDevice dev = texture->renderer->dev->dev;
struct wlr_vk_renderer *renderer =
vulkan_get_renderer(wlr_texture->renderer);
VkDevice dev = renderer->dev->dev;
// make sure assumptions are met
assert(src_x + width <= texture->wlr_texture.width);
@ -136,27 +137,59 @@ static bool write_pixels(struct wlr_texture *wlr_texture,
return true;
}
static bool vulkan_texture_write_pixels(struct wlr_texture *wlr_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 *vdata) {
return write_pixels(wlr_texture, stride, width, height, src_x, src_y,
dst_x, dst_y, vdata, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT);
static bool vulkan_texture_update_from_raster(struct wlr_texture *wlr_texture,
struct wlr_raster *raster, pixman_region32_t *damage) {
struct wlr_vk_texture *texture = vulkan_get_texture(wlr_texture);
struct wlr_buffer *buffer = raster->buffer;
void *data;
uint32_t format;
size_t stride;
if (!wlr_buffer_begin_data_ptr_access(buffer,
WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) {
return false;
}
bool ok = true;
if (format != texture->format->drm_format) {
ok = false;
goto out;
}
int rects_len = 0;
pixman_box32_t *rects = pixman_region32_rectangles(damage, &rects_len);
for (int i = 0; i < rects_len; i++) {
pixman_box32_t rect = rects[i];
uint32_t width = rect.x2 - rect.x1;
uint32_t height = rect.y2 - rect.y1;
// TODO: only map memory once
ok = write_pixels(wlr_texture, stride, width, height, rect.x1, rect.y1,
rect.x1, rect.y1, data, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT);
if (!ok) {
goto out;
}
}
out:
wlr_buffer_end_data_ptr_access(buffer);
return ok;
}
void vulkan_texture_destroy(struct wlr_vk_texture *texture) {
if (!texture->renderer) {
free(texture);
return;
}
struct wlr_vk_renderer *renderer =
vulkan_get_renderer(texture->wlr_texture.renderer);
// when we recorded a command to fill this image _this_ frame,
// it has to be executed before the texture can be destroyed.
// Add it to the renderer->destroy_textures list, destroying
// _after_ the stage command buffer has exectued
if (texture->last_used == texture->renderer->frame) {
if (texture->last_used == renderer->frame) {
assert(texture->destroy_link.next == NULL); // not already inserted
wl_list_insert(&texture->renderer->destroy_textures,
wl_list_insert(&renderer->destroy_textures,
&texture->destroy_link);
return;
}
@ -164,9 +197,9 @@ void vulkan_texture_destroy(struct wlr_vk_texture *texture) {
wl_list_remove(&texture->link);
wl_list_remove(&texture->buffer_destroy.link);
VkDevice dev = texture->renderer->dev->dev;
VkDevice dev = renderer->dev->dev;
if (texture->ds && texture->ds_pool) {
vulkan_free_ds(texture->renderer, texture->ds_pool, texture->ds);
vulkan_free_ds(renderer, texture->ds_pool, texture->ds);
}
vkDestroyImageView(dev, texture->image_view, NULL);
@ -191,7 +224,7 @@ static void vulkan_texture_unref(struct wlr_texture *wlr_texture) {
}
static const struct wlr_texture_impl texture_impl = {
.write_pixels = vulkan_texture_write_pixels,
.update_from_raster = vulkan_texture_update_from_raster,
.destroy = vulkan_texture_unref,
};
@ -203,18 +236,16 @@ static struct wlr_vk_texture *vulkan_texture_create(
wlr_log_errno(WLR_ERROR, "Allocation failed");
return NULL;
}
wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height);
texture->renderer = renderer;
wlr_texture_init(&texture->wlr_texture, &renderer->wlr_renderer,
&texture_impl, width, height);
wl_list_insert(&renderer->textures, &texture->link);
wl_list_init(&texture->buffer_destroy.link);
return texture;
}
static struct wlr_texture *vulkan_texture_from_pixels(struct wlr_renderer *wlr_renderer,
static struct wlr_vk_texture *vulkan_texture_from_pixels(struct wlr_vk_renderer *renderer,
uint32_t drm_fmt, uint32_t stride, uint32_t width,
uint32_t height, const void *data) {
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
VkResult res;
VkDevice dev = renderer->dev->dev;
@ -338,7 +369,7 @@ static struct wlr_texture *vulkan_texture_from_pixels(struct wlr_renderer *wlr_r
goto error;
}
return &texture->wlr_texture;
return texture;
error:
vulkan_texture_destroy(texture);
@ -573,7 +604,7 @@ error_image:
return VK_NULL_HANDLE;
}
static struct wlr_texture *vulkan_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
static struct wlr_vk_texture *vulkan_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
struct wlr_dmabuf_attributes *attribs) {
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
@ -648,7 +679,7 @@ static struct wlr_texture *vulkan_texture_from_dmabuf(struct wlr_renderer *wlr_r
vkUpdateDescriptorSets(dev, 1, &ds_write, 0, NULL);
texture->dmabuf_imported = true;
return &texture->wlr_texture;
return texture;
error:
vulkan_texture_destroy(texture);
@ -662,50 +693,69 @@ static void texture_handle_buffer_destroy(struct wl_listener *listener,
vulkan_texture_destroy(texture);
}
static struct wlr_texture *vulkan_texture_from_dmabuf_buffer(
static struct wlr_vk_texture *vulkan_texture_from_dmabuf_buffer(
struct wlr_vk_renderer *renderer, struct wlr_buffer *buffer,
struct wlr_dmabuf_attributes *dmabuf) {
struct wlr_vk_texture *texture;
wl_list_for_each(texture, &renderer->textures, link) {
if (texture->buffer == buffer) {
wlr_buffer_lock(texture->buffer);
return &texture->wlr_texture;
return texture;
}
}
struct wlr_texture *wlr_texture =
vulkan_texture_from_dmabuf(&renderer->wlr_renderer, dmabuf);
if (wlr_texture == NULL) {
return false;
texture = vulkan_texture_from_dmabuf(&renderer->wlr_renderer, dmabuf);
if (!texture) {
return NULL;
}
texture = vulkan_get_texture(wlr_texture);
texture->buffer = wlr_buffer_lock(buffer);
texture->buffer_destroy.notify = texture_handle_buffer_destroy;
wl_signal_add(&buffer->events.destroy, &texture->buffer_destroy);
return &texture->wlr_texture;
return texture;
}
struct wlr_texture *vulkan_texture_from_buffer(
struct wlr_renderer *wlr_renderer,
struct wlr_buffer *buffer) {
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
struct wlr_vk_texture *vulkan_raster_upload(struct wlr_vk_renderer *renderer,
struct wlr_raster *wlr_raster) {
struct wlr_texture *raster_texture;
wl_list_for_each(raster_texture, &wlr_raster->sources, link) {
if (wlr_texture_is_vk(raster_texture)) {
struct wlr_vk_texture *vk_tex =
(struct wlr_vk_texture *)raster_texture;
if (vk_tex->wlr_texture.renderer != &renderer->wlr_renderer) {
continue;
}
return vk_tex;
}
}
struct wlr_buffer *buffer = wlr_raster->buffer;
if (!wlr_raster->buffer) {
// we could possibly do a blit with another texture from another renderer,
// but this is unsupported currently.
return NULL;
}
struct wlr_vk_texture *texture = NULL;
void *data;
uint32_t format;
size_t stride;
struct wlr_dmabuf_attributes dmabuf;
if (wlr_buffer_get_dmabuf(buffer, &dmabuf)) {
return vulkan_texture_from_dmabuf_buffer(renderer, buffer, &dmabuf);
texture = vulkan_texture_from_dmabuf_buffer(renderer, buffer, &dmabuf);
} else if (wlr_buffer_begin_data_ptr_access(buffer,
WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) {
struct wlr_texture *tex = vulkan_texture_from_pixels(wlr_renderer,
texture = vulkan_texture_from_pixels(renderer,
format, stride, buffer->width, buffer->height, data);
wlr_buffer_end_data_ptr_access(buffer);
return tex;
} else {
return NULL;
}
if (texture) {
wlr_raster_attach(wlr_raster, &texture->wlr_texture);
}
return texture;
}

View file

@ -4,6 +4,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <drm_fourcc.h>
#include <wlr/render/interface.h>
#include <wlr/render/pixman.h>
#include <wlr/render/wlr_renderer.h>
@ -35,7 +36,8 @@ void wlr_renderer_init(struct wlr_renderer *renderer,
assert(impl->begin);
assert(impl->clear);
assert(impl->scissor);
assert(impl->render_subtexture_with_matrix);
assert(impl->raster_upload);
assert(impl->render_subraster_with_matrix);
assert(impl->render_quad_with_matrix);
assert(impl->get_shm_texture_formats);
assert(impl->get_render_buffer_caps);
@ -113,39 +115,92 @@ void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box) {
r->impl->scissor(r, box);
}
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) {
return r->impl->raster_upload(r, raster);
}
bool wlr_render_raster(struct wlr_renderer *r, struct wlr_raster *raster,
const float projection[static 9], int x, int y, float alpha) {
struct wlr_box box = {
.x = x,
.y = y,
.width = texture->width,
.height = texture->height,
.width = raster->width,
.height = raster->height,
};
float matrix[9];
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
projection);
return wlr_render_texture_with_matrix(r, texture, matrix, alpha);
return wlr_render_raster_with_matrix(r, raster, matrix, alpha);
}
bool wlr_render_texture_with_matrix(struct wlr_renderer *r,
struct wlr_texture *texture, const float matrix[static 9],
bool wlr_render_raster_with_matrix(struct wlr_renderer *r,
struct wlr_raster *raster, const float matrix[static 9],
float alpha) {
struct wlr_fbox box = {
.x = 0,
.y = 0,
.width = texture->width,
.height = texture->height,
.width = raster->width,
.height = raster->height,
};
return wlr_render_subtexture_with_matrix(r, texture, &box, matrix, alpha);
return wlr_render_subraster_with_matrix(r, raster, &box, matrix, alpha);
}
bool wlr_render_subtexture_with_matrix(struct wlr_renderer *r,
struct wlr_texture *texture, const struct wlr_fbox *box,
static bool try_single_pixel(struct wlr_buffer *buffer,
float color[static 4], const struct wlr_fbox *box, float alpha) {
if (box->width != 1.f || box->height != 1.f ||
box->x < 0.f || box->y < 0.f ||
box->x >= buffer->width || box->y >= buffer->height) {
return false;
}
uint32_t x = floor(box->x);
uint32_t y = floor(box->y);
if (box->x != (float)x || box->y != (float)y) {
return false;
}
void *data;
uint32_t format;
size_t stride;
if (!wlr_buffer_begin_data_ptr_access(buffer,
WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) {
return false;
}
if (format != DRM_FORMAT_ARGB8888) {
wlr_buffer_end_data_ptr_access(buffer);
return false;
}
size_t pixel_stride = stride / buffer->width;
uint8_t *data_color = &((uint8_t *)data)[pixel_stride * x + stride * y];
color[0] = data_color[3] * alpha / 255.f;
color[1] = data_color[2] * alpha / 255.f;
color[2] = data_color[1] * alpha / 255.f;
color[3] = data_color[0] * alpha / 255.f;
wlr_buffer_end_data_ptr_access(buffer);
return true;
}
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) {
assert(r->rendering);
return r->impl->render_subtexture_with_matrix(r, texture,
float color[4];
if (raster->buffer &&
try_single_pixel(raster->buffer, (float *)&color, box, alpha)) {
wlr_render_quad_with_matrix(r, color, matrix);
return true;
}
return r->impl->render_subraster_with_matrix(r, raster,
box, matrix, alpha);
}

View file

@ -4,80 +4,49 @@
#include <string.h>
#include <wlr/render/interface.h>
#include <wlr/render/wlr_texture.h>
#include <wlr/types/wlr_raster.h>
#include "types/wlr_buffer.h"
void wlr_texture_init(struct wlr_texture *texture,
void wlr_texture_init(struct wlr_texture *texture, struct wlr_renderer *renderer,
const struct wlr_texture_impl *impl, uint32_t width, uint32_t height) {
assert(renderer);
memset(texture, 0, sizeof(*texture));
texture->renderer = renderer;
texture->impl = impl;
texture->width = width;
texture->height = height;
}
void wlr_texture_destroy(struct wlr_texture *texture) {
if (texture && texture->impl && texture->impl->destroy) {
if (!texture) {
return;
}
if (texture->raster) {
wlr_raster_detach(texture->raster, texture);
texture->raster = NULL;
}
if (texture->impl && texture->impl->destroy) {
texture->impl->destroy(texture);
} else {
free(texture);
}
}
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) {
assert(width > 0);
assert(height > 0);
assert(stride > 0);
assert(data);
struct wlr_readonly_data_buffer *buffer =
readonly_data_buffer_create(fmt, stride, width, height, data);
if (buffer == NULL) {
return NULL;
}
struct wlr_texture *texture =
wlr_texture_from_buffer(renderer, &buffer->base);
// By this point, the renderer should have locked the buffer if it still
// needs to access it in the future.
readonly_data_buffer_drop(buffer);
return texture;
}
struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer,
struct wlr_dmabuf_attributes *attribs) {
struct wlr_dmabuf_buffer *buffer = dmabuf_buffer_create(attribs);
if (buffer == NULL) {
return NULL;
}
struct wlr_texture *texture =
wlr_texture_from_buffer(renderer, &buffer->base);
// By this point, the renderer should have locked the buffer if it still
// needs to access it in the future.
dmabuf_buffer_drop(buffer);
return texture;
}
struct wlr_texture *wlr_texture_from_buffer(struct wlr_renderer *renderer,
struct wlr_buffer *buffer) {
if (!renderer->impl->texture_from_buffer) {
return NULL;
}
return renderer->impl->texture_from_buffer(renderer, buffer);
}
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) {
if (!texture->impl->write_pixels) {
bool wlr_texture_update_from_raster(struct wlr_texture *texture,
struct wlr_raster *raster, pixman_region32_t *damage) {
if (!texture->impl->update_from_raster) {
return false;
}
return texture->impl->write_pixels(texture, stride, width, height,
src_x, src_y, dst_x, dst_y, data);
if (texture->width != raster->width || texture->height != raster->height) {
return false;
}
const pixman_box32_t *extents = pixman_region32_extents(damage);
if (extents->x1 < 0 || extents->y1 < 0 || extents->x2 > (int32_t)raster->width ||
extents->y2 > (int32_t)raster->height) {
return false;
}
return texture->impl->update_from_raster(texture, raster, damage);
}

View file

@ -343,12 +343,12 @@ static struct tinywl_view *desktop_view_at(
* surface in the surface tree of a tinywl_view. */
struct wlr_scene_node *node = wlr_scene_node_at(
&server->scene->tree.node, lx, ly, sx, sy);
if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER) {
if (node == NULL || node->type != WLR_SCENE_NODE_RASTER) {
return NULL;
}
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
struct wlr_scene_raster *scene_raster = wlr_scene_raster_from_node(node);
struct wlr_scene_surface *scene_surface =
wlr_scene_surface_from_buffer(scene_buffer);
wlr_scene_surface_from_raster(scene_raster);
if (!scene_surface) {
return NULL;
}
@ -853,7 +853,7 @@ int main(int argc, char *argv[]) {
* to dig your fingers in and play with their behavior if you want. Note that
* the clients cannot set the selection directly without compositor approval,
* see the handling of the request_set_selection event below.*/
wlr_compositor_create(server.wl_display, server.renderer);
wlr_compositor_create(server.wl_display);
wlr_subcompositor_create(server.wl_display);
wlr_data_device_manager_create(server.wl_display);

View file

@ -58,6 +58,7 @@ wlr_files += files(
'wlr_presentation_time.c',
'wlr_primary_selection_v1.c',
'wlr_primary_selection.c',
'wlr_raster.c',
'wlr_region.c',
'wlr_relative_pointer_v1.c',
'wlr_screencopy_v1.c',

View file

@ -93,11 +93,7 @@ static void output_cursor_render(struct wlr_output_cursor *cursor,
struct wlr_renderer *renderer = cursor->output->renderer;
assert(renderer);
struct wlr_texture *texture = cursor->texture;
if (cursor->surface != NULL) {
texture = wlr_surface_get_texture(cursor->surface);
}
if (texture == NULL) {
if (!cursor->raster) {
return;
}
@ -121,7 +117,7 @@ static void output_cursor_render(struct wlr_output_cursor *cursor,
pixman_box32_t *rects = pixman_region32_rectangles(&surface_damage, &nrects);
for (int i = 0; i < nrects; ++i) {
output_scissor(cursor->output, &rects[i]);
wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0f);
wlr_render_raster_with_matrix(renderer, cursor->raster, matrix, 1.0f);
}
wlr_renderer_scissor(renderer, NULL);
@ -234,29 +230,28 @@ static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor)
float scale = output->scale;
enum wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
struct wlr_texture *texture = cursor->texture;
if (cursor->surface != NULL) {
texture = wlr_surface_get_texture(cursor->surface);
scale = cursor->surface->current.scale;
transform = cursor->surface->current.transform;
}
if (texture == NULL) {
return NULL;
}
struct wlr_allocator *allocator = output->allocator;
struct wlr_renderer *renderer = output->renderer;
assert(allocator != NULL && renderer != NULL);
int width = texture->width;
int height = texture->height;
if (!cursor->raster) {
return NULL;
}
int width = cursor->raster->width;
int height = cursor->raster->height;
if (output->impl->get_cursor_size) {
// Apply hardware limitations on buffer size
output->impl->get_cursor_size(cursor->output, &width, &height);
if ((int)texture->width > width || (int)texture->height > height) {
wlr_log(WLR_DEBUG, "Cursor texture too large (%dx%d), "
"exceeds hardware limitations (%dx%d)", texture->width,
texture->height, width, height);
if ((int)cursor->raster->width > width || (int)cursor->raster->height > height) {
wlr_log(WLR_DEBUG, "Cursor raster too large (%dx%d), "
"exceeds hardware limitations (%dx%d)", cursor->raster->width,
cursor->raster->height, width, height);
return NULL;
}
}
@ -288,8 +283,8 @@ static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor)
}
struct wlr_box cursor_box = {
.width = texture->width * output->scale / scale,
.height = texture->height * output->scale / scale,
.width = cursor->raster->width * output->scale / scale,
.height = cursor->raster->height * output->scale / scale,
};
float output_matrix[9];
@ -317,7 +312,7 @@ static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor)
}
wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 0.0 });
wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0);
wlr_render_raster_with_matrix(renderer, cursor->raster, matrix, 1.0);
wlr_renderer_end(renderer);
@ -337,24 +332,16 @@ static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) {
return false;
}
struct wlr_texture *texture = cursor->texture;
if (cursor->surface != NULL) {
// TODO: try using the surface buffer directly
texture = wlr_surface_get_texture(cursor->surface);
}
// If the cursor was hidden or was a software cursor, the hardware
// cursor position is outdated
output->impl->move_cursor(cursor->output,
(int)cursor->x, (int)cursor->y);
struct wlr_buffer *buffer = NULL;
if (texture != NULL) {
buffer = render_cursor_buffer(cursor);
if (buffer == NULL) {
wlr_log(WLR_ERROR, "Failed to render cursor buffer");
return false;
}
buffer = render_cursor_buffer(cursor);
if (buffer == NULL) {
wlr_log(WLR_ERROR, "Failed to render cursor buffer");
return false;
}
struct wlr_box hotspot = {
@ -376,24 +363,20 @@ static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) {
bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,
const uint8_t *pixels, int32_t stride, uint32_t width, uint32_t height,
int32_t hotspot_x, int32_t hotspot_y) {
struct wlr_buffer *buffer = NULL;
struct wlr_raster *raster = NULL;
if (pixels) {
struct wlr_readonly_data_buffer *ro_buffer = readonly_data_buffer_create(
DRM_FORMAT_ARGB8888, stride, width, height, pixels);
if (ro_buffer == NULL) {
return false;
}
buffer = &ro_buffer->base;
raster = wlr_raster_from_pixels(DRM_FORMAT_ARGB8888,
stride, width, height, pixels);
}
bool ok = wlr_output_cursor_set_buffer(cursor, buffer, hotspot_x, hotspot_y);
bool ok = wlr_output_cursor_set_raster(cursor, raster, hotspot_x, hotspot_y);
wlr_buffer_drop(buffer);
wlr_raster_unlock(raster);
return ok;
}
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) {
struct wlr_renderer *renderer = cursor->output->renderer;
if (!renderer) {
return false;
@ -401,9 +384,9 @@ bool wlr_output_cursor_set_buffer(struct wlr_output_cursor *cursor,
output_cursor_reset(cursor);
if (buffer != NULL) {
cursor->width = buffer->width;
cursor->height = buffer->height;
if (raster) {
cursor->width = raster->width;
cursor->height = raster->height;
} else {
cursor->width = 0;
cursor->height = 0;
@ -414,16 +397,12 @@ bool wlr_output_cursor_set_buffer(struct wlr_output_cursor *cursor,
output_cursor_update_visible(cursor);
wlr_texture_destroy(cursor->texture);
cursor->texture = NULL;
wlr_raster_unlock(cursor->raster);
cursor->raster = NULL;
cursor->enabled = false;
if (buffer != NULL) {
cursor->texture = wlr_texture_from_buffer(renderer, buffer);
if (cursor->texture == NULL) {
return false;
}
cursor->enabled = true;
cursor->enabled = raster;
if (raster) {
cursor->raster = wlr_raster_lock(raster);
}
if (output_cursor_attempt_hardware(cursor)) {
@ -442,9 +421,16 @@ static void output_cursor_commit(struct wlr_output_cursor *cursor,
output_cursor_damage_whole(cursor);
}
wlr_raster_unlock(cursor->raster);
cursor->raster = NULL;
struct wlr_surface *surface = cursor->surface;
assert(surface != NULL);
if (surface->raster) {
cursor->raster = wlr_raster_lock(surface->raster);
}
// Some clients commit a cursor surface with a NULL buffer to hide it.
cursor->enabled = wlr_surface_has_buffer(surface);
cursor->width = surface->current.width * cursor->output->scale;
@ -589,7 +575,7 @@ void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) {
output_set_hardware_cursor(cursor->output, NULL, 0, 0);
cursor->output->hardware_cursor = NULL;
}
wlr_texture_destroy(cursor->texture);
wlr_raster_unlock(cursor->raster);
wl_list_remove(&cursor->link);
free(cursor);
}

View file

@ -81,9 +81,9 @@ static void subsurface_tree_reconfigure(
}
if (prev != NULL) {
wlr_scene_node_place_above(&subsurface_tree->scene_surface->buffer->node, prev);
wlr_scene_node_place_above(&subsurface_tree->scene_surface->raster->node, prev);
}
prev = &subsurface_tree->scene_surface->buffer->node;
prev = &subsurface_tree->scene_surface->raster->node;
wl_list_for_each(subsurface, &surface->current.subsurfaces_above,
current.link) {

View file

@ -3,7 +3,7 @@
#include <wlr/types/wlr_presentation_time.h>
#include "types/wlr_scene.h"
static void handle_scene_buffer_output_enter(
static void handle_scene_raster_output_enter(
struct wl_listener *listener, void *data) {
struct wlr_scene_surface *surface =
wl_container_of(listener, surface, output_enter);
@ -12,7 +12,7 @@ static void handle_scene_buffer_output_enter(
wlr_surface_send_enter(surface->surface, output->output);
}
static void handle_scene_buffer_output_leave(
static void handle_scene_raster_output_leave(
struct wl_listener *listener, void *data) {
struct wlr_scene_surface *surface =
wl_container_of(listener, surface, output_leave);
@ -21,14 +21,14 @@ static void handle_scene_buffer_output_leave(
wlr_surface_send_leave(surface->surface, output->output);
}
static void handle_scene_buffer_output_present(
static void handle_scene_raster_output_present(
struct wl_listener *listener, void *data) {
struct wlr_scene_surface *surface =
wl_container_of(listener, surface, output_present);
struct wlr_scene_output *scene_output = data;
if (surface->buffer->primary_output == scene_output) {
struct wlr_scene *root = scene_node_get_root(&surface->buffer->node);
if (surface->raster->primary_output == scene_output) {
struct wlr_scene *root = scene_node_get_root(&surface->raster->node);
struct wlr_presentation *presentation = root->presentation;
if (presentation) {
@ -38,7 +38,7 @@ static void handle_scene_buffer_output_present(
}
}
static void handle_scene_buffer_frame_done(
static void handle_scene_raster_frame_done(
struct wl_listener *listener, void *data) {
struct wlr_scene_surface *surface =
wl_container_of(listener, surface, frame_done);
@ -52,25 +52,27 @@ static void scene_surface_handle_surface_destroy(
struct wlr_scene_surface *surface =
wl_container_of(listener, surface, surface_destroy);
wlr_scene_node_destroy(&surface->buffer->node);
wlr_scene_node_destroy(&surface->raster->node);
}
static void set_buffer_with_surface_state(struct wlr_scene_buffer *scene_buffer,
static void set_raster_with_surface_state(struct wlr_scene_raster *scene_raster,
struct wlr_surface *surface) {
struct wlr_surface_state *state = &surface->current;
struct wlr_fbox src_box;
wlr_surface_get_buffer_source_box(surface, &src_box);
wlr_scene_buffer_set_source_box(scene_buffer, &src_box);
wlr_scene_raster_set_source_box(scene_raster, &src_box);
wlr_scene_buffer_set_dest_size(scene_buffer, state->width, state->height);
wlr_scene_buffer_set_transform(scene_buffer, state->transform);
wlr_scene_raster_set_dest_size(scene_raster, state->width, state->height);
wlr_scene_raster_set_transform(scene_raster, state->transform);
if (surface->buffer) {
wlr_scene_buffer_set_buffer_with_damage(scene_buffer,
&surface->buffer->base, &surface->buffer_damage);
struct wlr_raster *raster = surface->raster;
if (raster) {
wlr_scene_raster_set_raster_with_damage(scene_raster,
raster, &surface->buffer_damage);
} else {
wlr_scene_buffer_set_buffer(scene_buffer, NULL);
wlr_scene_raster_set_raster(scene_raster, NULL);
}
}
@ -78,27 +80,27 @@ static void handle_scene_surface_surface_commit(
struct wl_listener *listener, void *data) {
struct wlr_scene_surface *surface =
wl_container_of(listener, surface, surface_commit);
struct wlr_scene_buffer *scene_buffer = surface->buffer;
struct wlr_scene_raster *scene_raster = surface->raster;
set_buffer_with_surface_state(scene_buffer, surface->surface);
set_raster_with_surface_state(scene_raster, surface->surface);
// Even if the surface hasn't submitted damage, schedule a new frame if
// the client has requested a wl_surface.frame callback. Check if the node
// is visible. If not, the client will never receive a frame_done event
// anyway so it doesn't make sense to schedule here.
int lx, ly;
bool enabled = wlr_scene_node_coords(&scene_buffer->node, &lx, &ly);
bool enabled = wlr_scene_node_coords(&scene_raster->node, &lx, &ly);
if (!wl_list_empty(&surface->surface->current.frame_callback_list) &&
surface->buffer->primary_output != NULL && enabled) {
wlr_output_schedule_frame(surface->buffer->primary_output->output);
surface->raster->primary_output != NULL && enabled) {
wlr_output_schedule_frame(surface->raster->primary_output->output);
}
}
static bool scene_buffer_point_accepts_input(struct wlr_scene_buffer *scene_buffer,
static bool scene_raster_point_accepts_input(struct wlr_scene_raster *scene_raster,
int sx, int sy) {
struct wlr_scene_surface *scene_surface =
wlr_scene_surface_from_buffer(scene_buffer);
wlr_scene_surface_from_raster(scene_raster);
return wlr_surface_point_accepts_input(scene_surface->surface, sx, sy);
}
@ -123,10 +125,10 @@ static const struct wlr_addon_interface surface_addon_impl = {
.destroy = surface_addon_destroy,
};
struct wlr_scene_surface *wlr_scene_surface_from_buffer(
struct wlr_scene_buffer *scene_buffer) {
struct wlr_addon *addon = wlr_addon_find(&scene_buffer->node.addons,
scene_buffer, &surface_addon_impl);
struct wlr_scene_surface *wlr_scene_surface_from_raster(
struct wlr_scene_raster *scene_raster) {
struct wlr_addon *addon = wlr_addon_find(&scene_raster->node.addons,
scene_raster, &surface_addon_impl);
if (!addon) {
return NULL;
}
@ -142,27 +144,27 @@ struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_tree *parent
return NULL;
}
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_create(parent, NULL);
if (!scene_buffer) {
struct wlr_scene_raster *scene_raster = wlr_scene_raster_create(parent, NULL);
if (!scene_raster) {
free(surface);
return NULL;
}
surface->buffer = scene_buffer;
surface->raster = scene_raster;
surface->surface = wlr_surface;
scene_buffer->point_accepts_input = scene_buffer_point_accepts_input;
scene_raster->point_accepts_input = scene_raster_point_accepts_input;
surface->output_enter.notify = handle_scene_buffer_output_enter;
wl_signal_add(&scene_buffer->events.output_enter, &surface->output_enter);
surface->output_enter.notify = handle_scene_raster_output_enter;
wl_signal_add(&scene_raster->events.output_enter, &surface->output_enter);
surface->output_leave.notify = handle_scene_buffer_output_leave;
wl_signal_add(&scene_buffer->events.output_leave, &surface->output_leave);
surface->output_leave.notify = handle_scene_raster_output_leave;
wl_signal_add(&scene_raster->events.output_leave, &surface->output_leave);
surface->output_present.notify = handle_scene_buffer_output_present;
wl_signal_add(&scene_buffer->events.output_present, &surface->output_present);
surface->output_present.notify = handle_scene_raster_output_present;
wl_signal_add(&scene_raster->events.output_present, &surface->output_present);
surface->frame_done.notify = handle_scene_buffer_frame_done;
wl_signal_add(&scene_buffer->events.frame_done, &surface->frame_done);
surface->frame_done.notify = handle_scene_raster_frame_done;
wl_signal_add(&scene_raster->events.frame_done, &surface->frame_done);
surface->surface_destroy.notify = scene_surface_handle_surface_destroy;
wl_signal_add(&wlr_surface->events.destroy, &surface->surface_destroy);
@ -170,10 +172,10 @@ struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_tree *parent
surface->surface_commit.notify = handle_scene_surface_surface_commit;
wl_signal_add(&wlr_surface->events.commit, &surface->surface_commit);
wlr_addon_init(&surface->addon, &scene_buffer->node.addons,
scene_buffer, &surface_addon_impl);
wlr_addon_init(&surface->addon, &scene_raster->node.addons,
scene_raster, &surface_addon_impl);
set_buffer_with_surface_state(scene_buffer, wlr_surface);
set_raster_with_surface_state(scene_raster, wlr_surface);
return surface;
}

View file

@ -28,10 +28,10 @@ static struct wlr_scene_rect *scene_rect_from_node(
return (struct wlr_scene_rect *)node;
}
struct wlr_scene_buffer *wlr_scene_buffer_from_node(
struct wlr_scene_raster *wlr_scene_raster_from_node(
struct wlr_scene_node *node) {
assert(node->type == WLR_SCENE_NODE_BUFFER);
return (struct wlr_scene_buffer *)node;
assert(node->type == WLR_SCENE_NODE_RASTER);
return (struct wlr_scene_raster *)node;
}
struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) {
@ -87,22 +87,21 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) {
wlr_signal_emit_safe(&node->events.destroy, NULL);
struct wlr_scene *scene = scene_node_get_root(node);
if (node->type == WLR_SCENE_NODE_BUFFER) {
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
if (node->type == WLR_SCENE_NODE_RASTER) {
struct wlr_scene_raster *scene_raster = wlr_scene_raster_from_node(node);
uint64_t active = scene_buffer->active_outputs;
uint64_t active = scene_raster->active_outputs;
if (active) {
struct wlr_scene_output *scene_output;
wl_list_for_each(scene_output, &scene->outputs, link) {
if (active & (1ull << scene_output->index)) {
wlr_signal_emit_safe(&scene_buffer->events.output_leave,
wlr_signal_emit_safe(&scene_raster->events.output_leave,
scene_output);
}
}
}
wlr_texture_destroy(scene_buffer->texture);
wlr_buffer_unlock(scene_buffer->buffer);
wlr_raster_unlock(scene_raster->raster);
} else if (node->type == WLR_SCENE_NODE_TREE) {
struct wlr_scene_tree *scene_tree = scene_tree_from_node(node);
@ -196,16 +195,16 @@ struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent) {
static void scene_node_get_size(struct wlr_scene_node *node, int *lx, int *ly);
// This function must be called whenever the coordinates/dimensions of a scene
// buffer or scene output change. It is not necessary to call when a scene
// buffer's node is enabled/disabled or obscured by other nodes.
static void scene_buffer_update_outputs(struct wlr_scene_buffer *scene_buffer,
// raster or scene output change. It is not necessary to call when a scene
// raster's node is enabled/disabled or obscured by other nodes.
static void scene_raster_update_outputs(struct wlr_scene_raster *scene_raster,
int lx, int ly, struct wlr_scene *scene,
struct wlr_scene_output *ignore) {
struct wlr_box buffer_box = { .x = lx, .y = ly };
scene_node_get_size(&scene_buffer->node, &buffer_box.width, &buffer_box.height);
struct wlr_box raster_box = { .x = lx, .y = ly };
scene_node_get_size(&scene_raster->node, &raster_box.width, &raster_box.height);
int largest_overlap = 0;
scene_buffer->primary_output = NULL;
scene_raster->primary_output = NULL;
uint64_t active_outputs = 0;
@ -229,21 +228,21 @@ static void scene_buffer_update_outputs(struct wlr_scene_buffer *scene_buffer,
&output_box.width, &output_box.height);
struct wlr_box intersection;
bool intersects = wlr_box_intersection(&intersection, &buffer_box, &output_box);
bool intersects = wlr_box_intersection(&intersection, &raster_box, &output_box);
if (intersects) {
int overlap = intersection.width * intersection.height;
if (overlap > largest_overlap) {
largest_overlap = overlap;
scene_buffer->primary_output = scene_output;
scene_raster->primary_output = scene_output;
}
active_outputs |= 1ull << scene_output->index;
}
}
uint64_t old_active = scene_buffer->active_outputs;
scene_buffer->active_outputs = active_outputs;
uint64_t old_active = scene_raster->active_outputs;
scene_raster->active_outputs = active_outputs;
wl_list_for_each(scene_output, &scene->outputs, link) {
uint64_t mask = 1ull << scene_output->index;
@ -251,9 +250,9 @@ static void scene_buffer_update_outputs(struct wlr_scene_buffer *scene_buffer,
bool intersects_before = old_active & mask;
if (intersects && !intersects_before) {
wlr_signal_emit_safe(&scene_buffer->events.output_enter, scene_output);
wlr_signal_emit_safe(&scene_raster->events.output_enter, scene_output);
} else if (!intersects && intersects_before) {
wlr_signal_emit_safe(&scene_buffer->events.output_leave, scene_output);
wlr_signal_emit_safe(&scene_raster->events.output_leave, scene_output);
}
}
}
@ -261,10 +260,10 @@ static void scene_buffer_update_outputs(struct wlr_scene_buffer *scene_buffer,
static void _scene_node_update_outputs(struct wlr_scene_node *node,
int lx, int ly, struct wlr_scene *scene,
struct wlr_scene_output *ignore) {
if (node->type == WLR_SCENE_NODE_BUFFER) {
struct wlr_scene_buffer *scene_buffer =
wlr_scene_buffer_from_node(node);
scene_buffer_update_outputs(scene_buffer, lx, ly, scene, ignore);
if (node->type == WLR_SCENE_NODE_RASTER) {
struct wlr_scene_raster *scene_raster =
wlr_scene_raster_from_node(node);
scene_raster_update_outputs(scene_raster, lx, ly, scene, ignore);
} else if (node->type == WLR_SCENE_NODE_TREE) {
struct wlr_scene_tree *scene_tree = scene_tree_from_node(node);
struct wlr_scene_node *child;
@ -322,57 +321,54 @@ void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[sta
scene_node_damage_whole(&rect->node);
}
struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
struct wlr_buffer *buffer) {
struct wlr_scene_buffer *scene_buffer = calloc(1, sizeof(*scene_buffer));
if (scene_buffer == NULL) {
struct wlr_scene_raster *wlr_scene_raster_create(struct wlr_scene_tree *parent,
struct wlr_raster *raster) {
struct wlr_scene_raster *scene_raster = calloc(1, sizeof(*scene_raster));
if (scene_raster == NULL) {
return NULL;
}
assert(parent);
scene_node_init(&scene_buffer->node, WLR_SCENE_NODE_BUFFER, parent);
scene_node_init(&scene_raster->node, WLR_SCENE_NODE_RASTER, parent);
if (buffer) {
scene_buffer->buffer = wlr_buffer_lock(buffer);
if (raster) {
scene_raster->raster = wlr_raster_lock(raster);
}
wl_signal_init(&scene_buffer->events.output_enter);
wl_signal_init(&scene_buffer->events.output_leave);
wl_signal_init(&scene_buffer->events.output_present);
wl_signal_init(&scene_buffer->events.frame_done);
wl_signal_init(&scene_raster->events.output_enter);
wl_signal_init(&scene_raster->events.output_leave);
wl_signal_init(&scene_raster->events.output_present);
wl_signal_init(&scene_raster->events.frame_done);
scene_node_damage_whole(&scene_buffer->node);
scene_node_damage_whole(&scene_raster->node);
scene_node_update_outputs(&scene_buffer->node, NULL);
scene_node_update_outputs(&scene_raster->node, NULL);
return scene_buffer;
return scene_raster;
}
void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer,
struct wlr_buffer *buffer, pixman_region32_t *damage) {
// specifying a region for a NULL buffer doesn't make sense. We need to know
// about the buffer to scale the buffer local coordinates down to scene
void wlr_scene_raster_set_raster_with_damage(struct wlr_scene_raster *scene_raster,
struct wlr_raster *raster, pixman_region32_t *damage) {
// specifying a region for a NULL raster doesn't make sense. We need to know
// about the raster to scale the raster local coordinates down to scene
// coordinates.
assert(buffer || !damage);
assert(raster || !damage);
if (buffer != scene_buffer->buffer) {
if (raster != scene_raster->raster) {
if (!damage) {
scene_node_damage_whole(&scene_buffer->node);
scene_node_damage_whole(&scene_raster->node);
}
wlr_texture_destroy(scene_buffer->texture);
scene_buffer->texture = NULL;
wlr_buffer_unlock(scene_buffer->buffer);
wlr_raster_unlock(scene_raster->raster);
scene_raster->raster = NULL;
if (buffer) {
scene_buffer->buffer = wlr_buffer_lock(buffer);
} else {
scene_buffer->buffer = NULL;
if (raster) {
scene_raster->raster = wlr_raster_lock(raster);
}
scene_node_update_outputs(&scene_buffer->node, NULL);
scene_node_update_outputs(&scene_raster->node, NULL);
if (!damage) {
scene_node_damage_whole(&scene_buffer->node);
scene_node_damage_whole(&scene_raster->node);
}
}
@ -381,41 +377,41 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff
}
int lx, ly;
if (!wlr_scene_node_coords(&scene_buffer->node, &lx, &ly)) {
if (!wlr_scene_node_coords(&scene_raster->node, &lx, &ly)) {
return;
}
struct wlr_fbox box = scene_buffer->src_box;
struct wlr_fbox box = scene_raster->src_box;
if (wlr_fbox_empty(&box)) {
box.x = 0;
box.y = 0;
if (scene_buffer->transform & WL_OUTPUT_TRANSFORM_90) {
box.width = buffer->height;
box.height = buffer->width;
if (scene_raster->transform & WL_OUTPUT_TRANSFORM_90) {
box.width = raster->height;
box.height = raster->width;
} else {
box.width = buffer->width;
box.height = buffer->height;
box.width = raster->width;
box.height = raster->height;
}
}
double scale_x, scale_y;
if (scene_buffer->dst_width || scene_buffer->dst_height) {
scale_x = scene_buffer->dst_width / box.width;
scale_y = scene_buffer->dst_height / box.height;
if (scene_raster->dst_width || scene_raster->dst_height) {
scale_x = scene_raster->dst_width / box.width;
scale_y = scene_raster->dst_height / box.height;
} else {
scale_x = buffer->width / box.width;
scale_y = buffer->height / box.height;
scale_x = raster->width / box.width;
scale_y = raster->height / box.height;
}
pixman_region32_t trans_damage;
pixman_region32_init(&trans_damage);
wlr_region_transform(&trans_damage, damage,
scene_buffer->transform, buffer->width, buffer->height);
scene_raster->transform, raster->width, raster->height);
pixman_region32_intersect_rect(&trans_damage, &trans_damage,
box.x, box.y, box.width, box.height);
struct wlr_scene *scene = scene_node_get_root(&scene_buffer->node);
struct wlr_scene *scene = scene_node_get_root(&scene_raster->node);
struct wlr_scene_output *scene_output;
wl_list_for_each(scene_output, &scene->outputs, link) {
float output_scale = scene_output->output->scale;
@ -435,14 +431,14 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff
pixman_region32_fini(&trans_damage);
}
void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer,
struct wlr_buffer *buffer) {
wlr_scene_buffer_set_buffer_with_damage(scene_buffer, buffer, NULL);
void wlr_scene_raster_set_raster(struct wlr_scene_raster *scene_raster,
struct wlr_raster *raster) {
wlr_scene_raster_set_raster_with_damage(scene_raster, raster, 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) {
struct wlr_fbox *cur = &scene_buffer->src_box;
struct wlr_fbox *cur = &scene_raster->src_box;
if ((wlr_fbox_empty(box) && wlr_fbox_empty(cur)) ||
(box != NULL && memcmp(cur, box, sizeof(*box)) == 0)) {
return;
@ -454,56 +450,39 @@ void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer,
memset(cur, 0, sizeof(*cur));
}
scene_node_damage_whole(&scene_buffer->node);
scene_node_damage_whole(&scene_raster->node);
}
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) {
if (scene_buffer->dst_width == width && scene_buffer->dst_height == height) {
if (scene_raster->dst_width == width && scene_raster->dst_height == height) {
return;
}
scene_node_damage_whole(&scene_buffer->node);
scene_buffer->dst_width = width;
scene_buffer->dst_height = height;
scene_node_damage_whole(&scene_buffer->node);
scene_node_damage_whole(&scene_raster->node);
scene_raster->dst_width = width;
scene_raster->dst_height = height;
scene_node_damage_whole(&scene_raster->node);
scene_node_update_outputs(&scene_buffer->node, NULL);
scene_node_update_outputs(&scene_raster->node, NULL);
}
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) {
if (scene_buffer->transform == transform) {
if (scene_raster->transform == transform) {
return;
}
scene_node_damage_whole(&scene_buffer->node);
scene_buffer->transform = transform;
scene_node_damage_whole(&scene_buffer->node);
scene_node_damage_whole(&scene_raster->node);
scene_raster->transform = transform;
scene_node_damage_whole(&scene_raster->node);
scene_node_update_outputs(&scene_buffer->node, NULL);
scene_node_update_outputs(&scene_raster->node, NULL);
}
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) {
wlr_signal_emit_safe(&scene_buffer->events.frame_done, now);
}
static struct wlr_texture *scene_buffer_get_texture(
struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) {
struct wlr_client_buffer *client_buffer =
wlr_client_buffer_get(scene_buffer->buffer);
if (client_buffer != NULL) {
return client_buffer->texture;
}
if (scene_buffer->texture != NULL) {
return scene_buffer->texture;
}
scene_buffer->texture =
wlr_texture_from_buffer(renderer, scene_buffer->buffer);
return scene_buffer->texture;
wlr_signal_emit_safe(&scene_raster->events.frame_done, now);
}
static void scene_node_get_size(struct wlr_scene_node *node,
@ -519,18 +498,18 @@ static void scene_node_get_size(struct wlr_scene_node *node,
*width = scene_rect->width;
*height = scene_rect->height;
break;
case WLR_SCENE_NODE_BUFFER:;
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
if (scene_buffer->dst_width > 0 && scene_buffer->dst_height > 0) {
*width = scene_buffer->dst_width;
*height = scene_buffer->dst_height;
} else if (scene_buffer->buffer) {
if (scene_buffer->transform & WL_OUTPUT_TRANSFORM_90) {
*height = scene_buffer->buffer->width;
*width = scene_buffer->buffer->height;
case WLR_SCENE_NODE_RASTER:;
struct wlr_scene_raster *scene_raster = wlr_scene_raster_from_node(node);
if (scene_raster->dst_width > 0 && scene_raster->dst_height > 0) {
*width = scene_raster->dst_width;
*height = scene_raster->dst_height;
} else if (scene_raster->raster) {
if (scene_raster->transform & WL_OUTPUT_TRANSFORM_90) {
*height = scene_raster->raster->width;
*width = scene_raster->raster->height;
} else {
*width = scene_buffer->buffer->width;
*height = scene_buffer->buffer->height;
*width = scene_raster->raster->width;
*height = scene_raster->raster->height;
}
}
break;
@ -718,8 +697,8 @@ bool wlr_scene_node_coords(struct wlr_scene_node *node,
return enabled;
}
static void scene_node_for_each_scene_buffer(struct wlr_scene_node *node,
int lx, int ly, wlr_scene_buffer_iterator_func_t user_iterator,
static void scene_node_for_each_scene_raster(struct wlr_scene_node *node,
int lx, int ly, wlr_scene_raster_iterator_func_t user_iterator,
void *user_data) {
if (!node->enabled) {
return;
@ -728,21 +707,21 @@ static void scene_node_for_each_scene_buffer(struct wlr_scene_node *node,
lx += node->x;
ly += node->y;
if (node->type == WLR_SCENE_NODE_BUFFER) {
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
user_iterator(scene_buffer, lx, ly, user_data);
if (node->type == WLR_SCENE_NODE_RASTER) {
struct wlr_scene_raster *scene_raster = wlr_scene_raster_from_node(node);
user_iterator(scene_raster, lx, ly, user_data);
} else if (node->type == WLR_SCENE_NODE_TREE) {
struct wlr_scene_tree *scene_tree = scene_tree_from_node(node);
struct wlr_scene_node *child;
wl_list_for_each(child, &scene_tree->children, link) {
scene_node_for_each_scene_buffer(child, lx, ly, user_iterator, user_data);
scene_node_for_each_scene_raster(child, lx, ly, user_iterator, user_data);
}
}
}
void wlr_scene_node_for_each_buffer(struct wlr_scene_node *node,
wlr_scene_buffer_iterator_func_t user_iterator, void *user_data) {
scene_node_for_each_scene_buffer(node, 0, 0, user_iterator, user_data);
void wlr_scene_node_for_each_raster(struct wlr_scene_node *node,
wlr_scene_raster_iterator_func_t user_iterator, void *user_data) {
scene_node_for_each_scene_raster(node, 0, 0, user_iterator, user_data);
}
struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node,
@ -773,11 +752,11 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node,
scene_node_get_size(node, &width, &height);
intersects = lx >= 0 && lx < width && ly >= 0 && ly < height;
break;
case WLR_SCENE_NODE_BUFFER:;
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
case WLR_SCENE_NODE_RASTER:;
struct wlr_scene_raster *scene_raster = wlr_scene_raster_from_node(node);
if (scene_buffer->point_accepts_input) {
intersects = scene_buffer->point_accepts_input(scene_buffer, lx, ly);
if (scene_raster->point_accepts_input) {
intersects = scene_raster->point_accepts_input(scene_raster, lx, ly);
} else {
int width, height;
scene_node_get_size(node, &width, &height);
@ -841,8 +820,8 @@ static void render_rect(struct wlr_output *output,
pixman_region32_fini(&damage);
}
static void render_texture(struct wlr_output *output,
pixman_region32_t *output_damage, struct wlr_texture *texture,
static void render_raster(struct wlr_output *output,
pixman_region32_t *output_damage, struct wlr_raster *raster,
const struct wlr_fbox *src_box, const struct wlr_box *dst_box,
const float matrix[static 9]) {
struct wlr_renderer *renderer = output->renderer;
@ -850,8 +829,8 @@ static void render_texture(struct wlr_output *output,
struct wlr_fbox default_src_box = {0};
if (wlr_fbox_empty(src_box)) {
default_src_box.width = texture->width;
default_src_box.height = texture->height;
default_src_box.width = raster->width;
default_src_box.height = raster->height;
src_box = &default_src_box;
}
@ -865,7 +844,7 @@ static void render_texture(struct wlr_output *output,
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for (int i = 0; i < nrects; ++i) {
scissor_output(output, &rects[i]);
wlr_render_subtexture_with_matrix(renderer, texture, src_box, matrix, 1.0);
wlr_render_subraster_with_matrix(renderer, raster, src_box, matrix, 1.0);
}
pixman_region32_fini(&damage);
@ -890,7 +869,6 @@ static void render_node_iterator(struct wlr_scene_node *node,
scene_node_get_size(node, &dst_box.width, &dst_box.height);
scale_box(&dst_box, output->scale);
struct wlr_texture *texture;
float matrix[9];
enum wl_output_transform transform;
switch (node->type) {
@ -903,26 +881,20 @@ static void render_node_iterator(struct wlr_scene_node *node,
render_rect(output, output_damage, scene_rect->color, &dst_box,
output->transform_matrix);
break;
case WLR_SCENE_NODE_BUFFER:;
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
if (!scene_buffer->buffer) {
case WLR_SCENE_NODE_RASTER:;
struct wlr_scene_raster *scene_raster = wlr_scene_raster_from_node(node);
if (!scene_raster->raster) {
return;
}
struct wlr_renderer *renderer = output->renderer;
texture = scene_buffer_get_texture(scene_buffer, renderer);
if (texture == NULL) {
return;
}
transform = wlr_output_transform_invert(scene_buffer->transform);
transform = wlr_output_transform_invert(scene_raster->transform);
wlr_matrix_project_box(matrix, &dst_box, transform, 0.0,
output->transform_matrix);
render_texture(output, output_damage, texture, &scene_buffer->src_box,
&dst_box, matrix);
render_raster(output, output_damage, scene_raster->raster,
&scene_raster->src_box, &dst_box, matrix);
wlr_signal_emit_safe(&scene_buffer->events.output_present, scene_output);
wlr_signal_emit_safe(&scene_raster->events.output_present, scene_output);
break;
}
}
@ -1181,31 +1153,35 @@ static bool scene_output_scanout(struct wlr_scene_output *scene_output) {
}
struct wlr_scene_node *node = check_scanout_data.node;
struct wlr_buffer *buffer;
struct wlr_raster *raster;
switch (node->type) {
case WLR_SCENE_NODE_BUFFER:;
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
if (scene_buffer->buffer == NULL ||
!wlr_fbox_empty(&scene_buffer->src_box) ||
scene_buffer->transform != output->transform) {
case WLR_SCENE_NODE_RASTER:;
struct wlr_scene_raster *scene_raster = wlr_scene_raster_from_node(node);
if (scene_raster->raster == NULL ||
!wlr_fbox_empty(&scene_raster->src_box) ||
scene_raster->transform != output->transform) {
return false;
}
buffer = scene_buffer->buffer;
raster = scene_raster->raster;
break;
default:
return false;
}
wlr_output_attach_buffer(output, buffer);
if (!raster->buffer) {
return false;
}
wlr_output_attach_buffer(output, raster->buffer);
if (!wlr_output_test(output)) {
wlr_output_rollback(output);
return false;
}
if (node->type == WLR_SCENE_NODE_BUFFER) {
struct wlr_scene_buffer *scene_buffer =
wlr_scene_buffer_from_node(node);
wlr_signal_emit_safe(&scene_buffer->events.output_present, scene_output);
if (node->type == WLR_SCENE_NODE_RASTER) {
struct wlr_scene_raster *scene_raster =
wlr_scene_raster_from_node(node);
wlr_signal_emit_safe(&scene_raster->events.output_present, scene_output);
}
return wlr_output_commit(output);
@ -1371,12 +1347,12 @@ static void scene_node_send_frame_done(struct wlr_scene_node *node,
return;
}
if (node->type == WLR_SCENE_NODE_BUFFER) {
struct wlr_scene_buffer *scene_buffer =
wlr_scene_buffer_from_node(node);
if (node->type == WLR_SCENE_NODE_RASTER) {
struct wlr_scene_raster *scene_raster =
wlr_scene_raster_from_node(node);
if (scene_buffer->primary_output == scene_output) {
wlr_scene_buffer_send_frame_done(scene_buffer, now);
if (scene_raster->primary_output == scene_output) {
wlr_scene_raster_send_frame_done(scene_raster, now);
}
} else if (node->type == WLR_SCENE_NODE_TREE) {
struct wlr_scene_tree *scene_tree = scene_tree_from_node(node);
@ -1393,9 +1369,9 @@ void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output,
scene_output, now);
}
static void scene_output_for_each_scene_buffer(const struct wlr_box *output_box,
static void scene_output_for_each_scene_raster(const struct wlr_box *output_box,
struct wlr_scene_node *node, int lx, int ly,
wlr_scene_buffer_iterator_func_t user_iterator, void *user_data) {
wlr_scene_raster_iterator_func_t user_iterator, void *user_data) {
if (!node->enabled) {
return;
}
@ -1403,31 +1379,31 @@ static void scene_output_for_each_scene_buffer(const struct wlr_box *output_box,
lx += node->x;
ly += node->y;
if (node->type == WLR_SCENE_NODE_BUFFER) {
if (node->type == WLR_SCENE_NODE_RASTER) {
struct wlr_box node_box = { .x = lx, .y = ly };
scene_node_get_size(node, &node_box.width, &node_box.height);
struct wlr_box intersection;
if (wlr_box_intersection(&intersection, output_box, &node_box)) {
struct wlr_scene_buffer *scene_buffer =
wlr_scene_buffer_from_node(node);
user_iterator(scene_buffer, lx, ly, user_data);
struct wlr_scene_raster *scene_raster =
wlr_scene_raster_from_node(node);
user_iterator(scene_raster, lx, ly, user_data);
}
} else if (node->type == WLR_SCENE_NODE_TREE) {
struct wlr_scene_tree *scene_tree = scene_tree_from_node(node);
struct wlr_scene_node *child;
wl_list_for_each(child, &scene_tree->children, link) {
scene_output_for_each_scene_buffer(output_box, child, lx, ly,
scene_output_for_each_scene_raster(output_box, child, lx, ly,
user_iterator, user_data);
}
}
}
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) {
struct wlr_box box = { .x = scene_output->x, .y = scene_output->y };
wlr_output_effective_resolution(scene_output->output,
&box.width, &box.height);
scene_output_for_each_scene_buffer(&box, &scene_output->scene->tree.node, 0, 0,
scene_output_for_each_scene_raster(&box, &scene_output->scene->tree.node, 0, 0,
iterator, user_data);
}

View file

@ -109,59 +109,8 @@ bool wlr_resource_is_buffer(struct wl_resource *resource) {
return strcmp(wl_resource_get_class(resource), wl_buffer_interface.name) == 0;
}
static const struct wlr_buffer_impl client_buffer_impl;
struct wlr_client_buffer *wlr_client_buffer_get(struct wlr_buffer *buffer) {
if (buffer->impl != &client_buffer_impl) {
return NULL;
}
return (struct wlr_client_buffer *)buffer;
}
static struct wlr_client_buffer *client_buffer_from_buffer(
struct wlr_buffer *buffer) {
struct wlr_client_buffer *client_buffer = wlr_client_buffer_get(buffer);
assert(client_buffer != NULL);
return client_buffer;
}
static void client_buffer_destroy(struct wlr_buffer *buffer) {
struct wlr_client_buffer *client_buffer = client_buffer_from_buffer(buffer);
wl_list_remove(&client_buffer->source_destroy.link);
wlr_texture_destroy(client_buffer->texture);
free(client_buffer);
}
static bool client_buffer_get_dmabuf(struct wlr_buffer *buffer,
struct wlr_dmabuf_attributes *attribs) {
struct wlr_client_buffer *client_buffer = client_buffer_from_buffer(buffer);
if (client_buffer->source == NULL) {
return false;
}
return wlr_buffer_get_dmabuf(client_buffer->source, attribs);
}
static const struct wlr_buffer_impl client_buffer_impl = {
.destroy = client_buffer_destroy,
.get_dmabuf = client_buffer_get_dmabuf,
};
static void client_buffer_handle_source_destroy(struct wl_listener *listener,
void *data) {
struct wlr_client_buffer *client_buffer =
wl_container_of(listener, client_buffer, source_destroy);
wl_list_remove(&client_buffer->source_destroy.link);
wl_list_init(&client_buffer->source_destroy.link);
client_buffer->source = NULL;
}
static struct wlr_shm_client_buffer *shm_client_buffer_get_or_create(
struct wl_resource *resource);
static bool buffer_is_shm_client_buffer(struct wlr_buffer *buffer);
static struct wlr_shm_client_buffer *shm_client_buffer_from_buffer(
struct wlr_buffer *buffer);
/* struct wlr_buffer_resource_interface */
static struct wl_array buffer_resource_interfaces = {0};
@ -263,99 +212,13 @@ bool buffer_is_opaque(struct wlr_buffer *buffer) {
return !format_info->has_alpha;
}
struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer,
struct wlr_renderer *renderer) {
struct wlr_texture *texture = wlr_texture_from_buffer(renderer, buffer);
if (texture == NULL) {
wlr_log(WLR_ERROR, "Failed to create texture");
return NULL;
}
struct wlr_client_buffer *client_buffer =
calloc(1, sizeof(struct wlr_client_buffer));
if (client_buffer == NULL) {
wlr_texture_destroy(texture);
return NULL;
}
wlr_buffer_init(&client_buffer->base, &client_buffer_impl,
texture->width, texture->height);
client_buffer->source = buffer;
client_buffer->texture = texture;
wl_signal_add(&buffer->events.destroy, &client_buffer->source_destroy);
client_buffer->source_destroy.notify = client_buffer_handle_source_destroy;
if (buffer_is_shm_client_buffer(buffer)) {
struct wlr_shm_client_buffer *shm_client_buffer =
shm_client_buffer_from_buffer(buffer);
client_buffer->shm_source_format = shm_client_buffer->format;
} else {
client_buffer->shm_source_format = DRM_FORMAT_INVALID;
}
// Ensure the buffer will be released before being destroyed
wlr_buffer_lock(&client_buffer->base);
wlr_buffer_drop(&client_buffer->base);
return client_buffer;
}
bool wlr_client_buffer_apply_damage(struct wlr_client_buffer *client_buffer,
struct wlr_buffer *next, pixman_region32_t *damage) {
if (client_buffer->base.n_locks > 1) {
// Someone else still has a reference to the buffer
return false;
}
if ((uint32_t)next->width != client_buffer->texture->width ||
(uint32_t)next->height != client_buffer->texture->height) {
return false;
}
if (client_buffer->shm_source_format == DRM_FORMAT_INVALID) {
// Uploading only damaged regions only works for wl_shm buffers and
// mutable textures (created from wl_shm buffer)
return false;
}
void *data;
uint32_t format;
size_t stride;
if (!wlr_buffer_begin_data_ptr_access(next, WLR_BUFFER_DATA_PTR_ACCESS_READ,
&data, &format, &stride)) {
return false;
}
if (format != client_buffer->shm_source_format) {
// Uploading to textures can't change the format
wlr_buffer_end_data_ptr_access(next);
return false;
}
int n;
pixman_box32_t *rects = pixman_region32_rectangles(damage, &n);
for (int i = 0; i < n; ++i) {
pixman_box32_t *r = &rects[i];
if (!wlr_texture_write_pixels(client_buffer->texture, stride,
r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1,
r->x1, r->y1, data)) {
wlr_buffer_end_data_ptr_access(next);
return false;
}
}
wlr_buffer_end_data_ptr_access(next);
return true;
}
static const struct wlr_buffer_impl shm_client_buffer_impl;
static bool buffer_is_shm_client_buffer(struct wlr_buffer *buffer) {
bool buffer_is_shm_client_buffer(struct wlr_buffer *buffer) {
return buffer->impl == &shm_client_buffer_impl;
}
static struct wlr_shm_client_buffer *shm_client_buffer_from_buffer(
struct wlr_shm_client_buffer *shm_client_buffer_from_buffer(
struct wlr_buffer *buffer) {
assert(buffer_is_shm_client_buffer(buffer));
return (struct wlr_shm_client_buffer *)buffer;

View file

@ -1,6 +1,7 @@
#include <assert.h>
#include <stdlib.h>
#include <wayland-server-core.h>
#include <wlr/interfaces/wlr_buffer.h>
#include <wlr/render/interface.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_compositor.h>
@ -333,45 +334,15 @@ static void surface_state_move(struct wlr_surface_state *state,
static void surface_apply_damage(struct wlr_surface *surface) {
if (surface->current.buffer == NULL) {
// NULL commit
if (surface->buffer != NULL) {
wlr_buffer_unlock(&surface->buffer->base);
}
surface->buffer = NULL;
surface->opaque = false;
return;
}
surface->opaque = buffer_is_opaque(surface->current.buffer);
if (surface->buffer != NULL) {
if (wlr_client_buffer_apply_damage(surface->buffer,
surface->current.buffer, &surface->buffer_damage)) {
wlr_buffer_unlock(surface->current.buffer);
surface->current.buffer = NULL;
return;
}
}
struct wlr_client_buffer *buffer = wlr_client_buffer_create(
surface->current.buffer, surface->renderer);
wlr_buffer_unlock(surface->current.buffer);
surface->current.buffer = NULL;
if (buffer == NULL) {
wlr_log(WLR_ERROR, "Failed to upload buffer");
return;
}
if (surface->buffer != NULL) {
wlr_buffer_unlock(&surface->buffer->base);
}
surface->buffer = buffer;
}
static void surface_update_opaque_region(struct wlr_surface *surface) {
struct wlr_texture *texture = wlr_surface_get_texture(surface);
if (texture == NULL) {
if (!wlr_surface_has_buffer(surface)) {
pixman_region32_clear(&surface->opaque_region);
return;
}
@ -445,8 +416,34 @@ static void surface_commit_state(struct wlr_surface *surface,
surface_state_move(&surface->current, next);
if (invalid_buffer) {
if (!surface->current.buffer) {
wlr_raster_unlock(surface->raster);
surface->raster = NULL;
}
if (!surface->raster || surface->raster->buffer != surface->current.buffer) {
surface->old_raster = surface->raster;
if (surface->current.buffer) {
surface->raster = wlr_raster_create(surface->current.buffer);
}
if (surface->old_raster) {
// By the time we unlock the buffer next the buffer might
// get destroyed. We need to start listening here.
wl_signal_add(&surface->old_raster->events.destroy,
&surface->raster_destroy);
wlr_raster_unlock(surface->old_raster);
}
}
surface_apply_damage(surface);
wlr_buffer_unlock(surface->current.buffer);
surface->current.buffer = NULL;
}
surface_update_opaque_region(surface);
surface_update_input_region(surface);
@ -480,6 +477,37 @@ static void surface_commit_state(struct wlr_surface *surface,
}
wlr_signal_emit_safe(&surface->events.commit, surface);
if (surface->old_raster) {
wl_list_remove(&surface->raster_destroy.link);
surface->old_raster = NULL;
}
if (invalid_buffer && surface->raster) {
// upload the texture to all renderers that this surface intersects.
struct wlr_surface_output *surface_output;
wl_list_for_each(surface_output, &surface->current_outputs, link) {
if (!surface_output->output->renderer) {
continue;
}
wlr_renderer_raster_upload(surface_output->output->renderer,
surface->raster);
}
// unlock the buffer for shm buffers only. Clients may implement
// optimizations if given the shm buffer back immediately. But only do
// this if the raster has a source, if not, that means that the surface
// is not visible on any outputs and let's continue locking the buffer
// until it is visible.
//
// For other buffers, we want to continue to lock it so that we
// may direct scanout.
if (!wl_list_empty(&surface->raster->sources) && surface->raster->buffer &&
buffer_is_shm_client_buffer(surface->raster->buffer)) {
wlr_raster_remove_buffer(surface->raster);
}
}
}
static void collect_subsurface_damage_iter(struct wlr_surface *surface,
@ -644,6 +672,8 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) {
surface_output_destroy(surface_output);
}
wlr_raster_unlock(surface->raster);
wlr_signal_emit_safe(&surface->events.destroy, surface);
wlr_addon_set_finish(&surface->addons);
@ -653,28 +683,63 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) {
surface_state_destroy_cached(cached);
}
wl_list_remove(&surface->renderer_destroy.link);
surface_state_finish(&surface->pending);
surface_state_finish(&surface->current);
pixman_region32_fini(&surface->buffer_damage);
pixman_region32_fini(&surface->external_damage);
pixman_region32_fini(&surface->opaque_region);
pixman_region32_fini(&surface->input_region);
if (surface->buffer != NULL) {
wlr_buffer_unlock(&surface->buffer->base);
}
free(surface);
}
static void surface_handle_renderer_destroy(struct wl_listener *listener,
void *data) {
static void surface_handle_raster_destroy(struct wl_listener *listener, void *data) {
struct wlr_surface *surface =
wl_container_of(listener, surface, renderer_destroy);
wl_resource_destroy(surface->resource);
wl_container_of(listener, surface, raster_destroy);
// if there are already sources for the new raster, don't bother uploading
// if something else already did for us.
if (!wl_list_empty(&surface->raster->sources)) {
surface->old_raster = NULL;
return;
}
// try to reclaim the textures from this raster so we can try to do a partial
// upload.
struct wlr_texture *texture, *tmp_texture;
wl_list_for_each_safe(texture, tmp_texture,
&surface->old_raster->sources, link) {
wlr_raster_detach(surface->old_raster, texture);
bool visible = false;
// only try to reuse textures of renderers that will see this surface.
struct wlr_surface_output *surface_output;
wl_list_for_each(surface_output, &surface->current_outputs, link) {
if (surface_output->output->renderer == texture->renderer) {
visible = true;
break;
}
}
if (!visible) {
wlr_texture_destroy(texture);
continue;
}
if (!wlr_texture_update_from_raster(texture,
surface->raster, &surface->buffer_damage)) {
wlr_texture_destroy(texture);
continue;
}
wlr_raster_attach(surface->raster, texture);
}
surface->old_raster = NULL;
}
static struct wlr_surface *surface_create(struct wl_client *client,
uint32_t version, uint32_t id, struct wlr_renderer *renderer) {
uint32_t version, uint32_t id) {
struct wlr_surface *surface = calloc(1, sizeof(struct wlr_surface));
if (!surface) {
wl_client_post_no_memory(client);
@ -692,8 +757,6 @@ static struct wlr_surface *surface_create(struct wl_client *client,
wlr_log(WLR_DEBUG, "New wlr_surface %p (res %p)", surface, surface->resource);
surface->renderer = renderer;
surface_state_init(&surface->current);
surface_state_init(&surface->pending);
surface->pending.seq = 1;
@ -710,21 +773,13 @@ static struct wlr_surface *surface_create(struct wl_client *client,
pixman_region32_init(&surface->input_region);
wlr_addon_set_init(&surface->addons);
wl_signal_add(&renderer->events.destroy, &surface->renderer_destroy);
surface->renderer_destroy.notify = surface_handle_renderer_destroy;
surface->raster_destroy.notify = surface_handle_raster_destroy;
return surface;
}
struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface) {
if (surface->buffer == NULL) {
return NULL;
}
return surface->buffer->texture;
}
bool wlr_surface_has_buffer(struct wlr_surface *surface) {
return wlr_surface_get_texture(surface) != NULL;
return surface->raster != NULL;
}
bool wlr_surface_set_role(struct wlr_surface *surface,
@ -1097,7 +1152,7 @@ static void compositor_create_surface(struct wl_client *client,
struct wlr_compositor *compositor = compositor_from_resource(resource);
struct wlr_surface *surface = surface_create(client,
wl_resource_get_version(resource), id, compositor->renderer);
wl_resource_get_version(resource), id);
if (surface == NULL) {
wl_client_post_no_memory(client);
return;
@ -1139,8 +1194,7 @@ static void compositor_handle_display_destroy(
free(compositor);
}
struct wlr_compositor *wlr_compositor_create(struct wl_display *display,
struct wlr_renderer *renderer) {
struct wlr_compositor *wlr_compositor_create(struct wl_display *display) {
struct wlr_compositor *compositor = calloc(1, sizeof(*compositor));
if (!compositor) {
return NULL;
@ -1152,7 +1206,6 @@ struct wlr_compositor *wlr_compositor_create(struct wl_display *display,
free(compositor);
return NULL;
}
compositor->renderer = renderer;
wl_signal_init(&compositor->events.new_surface);
wl_signal_init(&compositor->events.destroy);

View file

@ -86,6 +86,10 @@ struct wlr_dmabuf_v1_buffer *wlr_dmabuf_v1_buffer_from_buffer_resource(
static const struct wlr_buffer_impl buffer_impl;
bool wlr_dmabuf_v1_buffer_is_buffer(struct wlr_buffer *buffer) {
return buffer->impl == &buffer_impl;
}
static struct wlr_dmabuf_v1_buffer *dmabuf_v1_buffer_from_buffer(
struct wlr_buffer *buffer) {
assert(buffer->impl == &buffer_impl);
@ -197,17 +201,15 @@ static void buffer_handle_resource_destroy(struct wl_resource *buffer_resource)
}
static bool check_import_dmabuf(struct wlr_linux_dmabuf_v1 *linux_dmabuf,
struct wlr_dmabuf_attributes *attribs) {
struct wlr_texture *texture =
wlr_texture_from_dmabuf(linux_dmabuf->renderer, attribs);
if (texture == NULL) {
struct wlr_buffer *dmabuf) {
struct wlr_raster *raster = wlr_raster_create(dmabuf);
if (!raster) {
return false;
}
// We can import the image, good. No need to keep it since wlr_surface will
// import it again on commit.
wlr_texture_destroy(texture);
return true;
bool success = wlr_renderer_raster_upload(linux_dmabuf->renderer, raster);
wlr_raster_unlock(raster);
return success;
}
static void params_create_common(struct wl_resource *params_resource,
@ -327,17 +329,19 @@ static void params_create_common(struct wl_resource *params_resource,
}
}
/* Check if dmabuf is usable */
if (!check_import_dmabuf(linux_dmabuf, &attribs)) {
goto err_failed;
}
struct wlr_dmabuf_v1_buffer *buffer = calloc(1, sizeof(*buffer));
if (!buffer) {
wl_resource_post_no_memory(params_resource);
goto err_failed;
}
wlr_buffer_init(&buffer->base, &buffer_impl, attribs.width, attribs.height);
buffer->attributes = attribs;
/* Check if dmabuf is usable */
if (!check_import_dmabuf(linux_dmabuf, &buffer->base)) {
free(buffer);
goto err_failed;
}
struct wl_client *client = wl_resource_get_client(params_resource);
buffer->resource = wl_resource_create(client, &wl_buffer_interface,
@ -350,8 +354,6 @@ static void params_create_common(struct wl_resource *params_resource,
wl_resource_set_implementation(buffer->resource,
&wl_buffer_impl, buffer, buffer_handle_resource_destroy);
buffer->attributes = attribs;
buffer->release.notify = buffer_handle_release;
wl_signal_add(&buffer->base.events.release, &buffer->release);

103
types/wlr_raster.c Normal file
View file

@ -0,0 +1,103 @@
#include <assert.h>
#include <wlr/types/wlr_raster.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/render/wlr_texture.h>
#include "types/wlr_buffer.h"
#include "util/signal.h"
struct wlr_raster *wlr_raster_create(struct wlr_buffer *buffer) {
struct wlr_raster *raster = calloc(1, sizeof(*raster));
if (!raster) {
return NULL;
}
wl_list_init(&raster->sources);
wl_signal_init(&raster->events.destroy);
assert(buffer);
raster->width = buffer->width;
raster->height = buffer->height;
raster->buffer = wlr_buffer_lock(buffer);
raster->n_locks = 1;
return raster;
}
void wlr_raster_remove_buffer(struct wlr_raster *raster) {
assert(raster->buffer);
assert(!wl_list_empty(&raster->sources));
wlr_buffer_unlock(raster->buffer);
raster->buffer = NULL;
}
static void raster_consider_destroy(struct wlr_raster *raster) {
if (raster->n_locks > 0) {
return;
}
wlr_signal_emit_safe(&raster->events.destroy, NULL);
struct wlr_texture *texture, *texture_tmp;
wl_list_for_each_safe(texture, texture_tmp, &raster->sources, link) {
wlr_texture_destroy(texture);
}
wlr_buffer_unlock(raster->buffer);
free(raster);
}
struct wlr_raster *wlr_raster_lock(struct wlr_raster *raster) {
raster->n_locks++;
return raster;
}
void wlr_raster_unlock(struct wlr_raster *raster) {
if (!raster) {
return;
}
assert(raster->n_locks > 0);
raster->n_locks--;
raster_consider_destroy(raster);
}
void wlr_raster_attach(struct wlr_raster *raster, struct wlr_texture *texture) {
assert(texture);
assert(!texture->raster);
assert(texture->width == raster->width && texture->height == raster->height);
wl_list_insert(&raster->sources, &texture->link);
texture->raster = raster;
}
void wlr_raster_detach(struct wlr_raster *raster, struct wlr_texture *texture) {
if (!texture) {
return;
}
assert(texture->raster == raster);
texture->raster = NULL;
wl_list_remove(&texture->link);
}
struct wlr_raster *wlr_raster_from_pixels(uint32_t fmt, uint32_t stride,
uint32_t width, uint32_t height, const void *data) {
assert(data);
struct wlr_readonly_data_buffer *buffer =
readonly_data_buffer_create(fmt, stride, width, height, data);
if (buffer == NULL) {
return NULL;
}
struct wlr_raster *raster = wlr_raster_create(&buffer->base);
// By this point, the renderer should have locked the buffer if it still
// needs to access it in the future.
readonly_data_buffer_drop(buffer);
return raster;
}

View file

@ -226,14 +226,18 @@ static bool frame_shm_copy(struct wlr_screencopy_frame_v1 *frame,
static bool blit_dmabuf(struct wlr_renderer *renderer,
struct wlr_dmabuf_v1_buffer *dst_dmabuf,
struct wlr_buffer *src_buffer) {
struct wlr_buffer *dst_buffer = wlr_buffer_lock(&dst_dmabuf->base);
struct wlr_texture *src_tex =
wlr_texture_from_buffer(renderer, src_buffer);
if (src_tex == NULL) {
goto error_src_tex;
struct wlr_raster *raster = wlr_raster_create(src_buffer);
if (!raster){
return false;
}
if (!wlr_renderer_raster_upload(renderer, raster)) {
wlr_raster_unlock(raster);
return false;
}
struct wlr_buffer *dst_buffer = wlr_buffer_lock(&dst_dmabuf->base);
float mat[9];
wlr_matrix_identity(mat);
wlr_matrix_scale(mat, dst_buffer->width, dst_buffer->height);
@ -243,17 +247,16 @@ static bool blit_dmabuf(struct wlr_renderer *renderer,
}
wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 0.0 });
wlr_render_texture_with_matrix(renderer, src_tex, mat, 1.0f);
wlr_render_raster_with_matrix(renderer, raster, mat, 1.0f);
wlr_renderer_end(renderer);
wlr_texture_destroy(src_tex);
wlr_raster_unlock(raster);
wlr_buffer_unlock(dst_buffer);
return true;
error_renderer_begin:
wlr_texture_destroy(src_tex);
error_src_tex:
wlr_raster_unlock(raster);
wlr_buffer_unlock(dst_buffer);
return false;
}