mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-11-03 09:01:40 -05:00 
			
		
		
		
	Add wlr_compositor buffer API
This also rolls wlr_buffer into wlr_renderer as a user of this new API.
This commit is contained in:
		
							parent
							
								
									21db2418b7
								
							
						
					
					
						commit
						8630988eae
					
				
					 10 changed files with 518 additions and 370 deletions
				
			
		| 
						 | 
					@ -19,8 +19,10 @@ enum wlr_renderer_read_pixels_flags {
 | 
				
			||||||
	WLR_RENDERER_READ_PIXELS_Y_INVERT = 1,
 | 
						WLR_RENDERER_READ_PIXELS_Y_INVERT = 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_renderer_impl;
 | 
					struct wlr_compositor;
 | 
				
			||||||
 | 
					struct wlr_commit;
 | 
				
			||||||
struct wlr_drm_format_set;
 | 
					struct wlr_drm_format_set;
 | 
				
			||||||
 | 
					struct wlr_renderer_impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_renderer {
 | 
					struct wlr_renderer {
 | 
				
			||||||
	const struct wlr_renderer_impl *impl;
 | 
						const struct wlr_renderer_impl *impl;
 | 
				
			||||||
| 
						 | 
					@ -107,11 +109,14 @@ bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt,
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool wlr_renderer_format_supported(struct wlr_renderer *r,
 | 
					bool wlr_renderer_format_supported(struct wlr_renderer *r,
 | 
				
			||||||
	enum wl_shm_format fmt);
 | 
						enum wl_shm_format fmt);
 | 
				
			||||||
void wlr_renderer_init_wl_display(struct wlr_renderer *r,
 | 
					 | 
				
			||||||
	struct wl_display *wl_display);
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Destroys this wlr_renderer. Textures must be destroyed separately.
 | 
					 * Destroys this wlr_renderer. Textures must be destroyed separately.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void wlr_renderer_destroy(struct wlr_renderer *renderer);
 | 
					void wlr_renderer_destroy(struct wlr_renderer *renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_renderer_set_compositor(struct wlr_renderer *renderer,
 | 
				
			||||||
 | 
						struct wlr_compositor *comp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_texture *wlr_commit_get_texture(struct wlr_commit *commit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
install_headers(
 | 
					install_headers(
 | 
				
			||||||
	'wlr_box.h',
 | 
						'wlr_box.h',
 | 
				
			||||||
	'wlr_buffer.h',
 | 
					 | 
				
			||||||
	'wlr_compositor.h',
 | 
						'wlr_compositor.h',
 | 
				
			||||||
	'wlr_cursor.h',
 | 
						'wlr_cursor.h',
 | 
				
			||||||
	'wlr_data_control_v1.h',
 | 
						'wlr_data_control_v1.h',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,71 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * 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_BUFFER_H
 | 
					 | 
				
			||||||
#define WLR_TYPES_WLR_BUFFER_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pixman.h>
 | 
					 | 
				
			||||||
#include <wayland-server.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * A client buffer.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct wlr_buffer {
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * The buffer resource, if any. Will be NULL if the client destroys it.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	struct wl_resource *resource;
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * 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;
 | 
					 | 
				
			||||||
	bool released;
 | 
					 | 
				
			||||||
	size_t n_refs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wl_listener resource_destroy;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wlr_renderer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Check if a resource is a wl_buffer resource.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool wlr_resource_is_buffer(struct wl_resource *resource);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Get the size of a wl_buffer resource.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool wlr_buffer_get_resource_size(struct wl_resource *resource,
 | 
					 | 
				
			||||||
	struct wlr_renderer *renderer, int *width, int *height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Upload a buffer to the GPU and reference it.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer,
 | 
					 | 
				
			||||||
	struct wl_resource *resource);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Reference the buffer.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct wlr_buffer *wlr_buffer_ref(struct wlr_buffer *buffer);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Unreference the buffer. After this call, `buffer` may not be accessed
 | 
					 | 
				
			||||||
 * anymore.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void wlr_buffer_unref(struct wlr_buffer *buffer);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Try to update the buffer's content. On success, returns the updated buffer
 | 
					 | 
				
			||||||
 * and destroys the provided `buffer`. On error, `buffer` is intact and NULL is
 | 
					 | 
				
			||||||
 * returned.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Fails if there's more than one reference to the buffer or if the texture
 | 
					 | 
				
			||||||
 * isn't mutable.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct wlr_buffer *wlr_buffer_apply_damage(struct wlr_buffer *buffer,
 | 
					 | 
				
			||||||
	struct wl_resource *resource, pixman_region32_t *damage);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
| 
						 | 
					@ -9,20 +9,79 @@
 | 
				
			||||||
#ifndef WLR_TYPES_WLR_COMPOSITOR_H
 | 
					#ifndef WLR_TYPES_WLR_COMPOSITOR_H
 | 
				
			||||||
#define WLR_TYPES_WLR_COMPOSITOR_H
 | 
					#define WLR_TYPES_WLR_COMPOSITOR_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <pixman.h>
 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <wlr/render/wlr_renderer.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_commit;
 | 
					struct wlr_commit;
 | 
				
			||||||
struct wlr_output;
 | 
					struct wlr_output;
 | 
				
			||||||
struct wlr_surface;
 | 
					struct wlr_surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This represents a client-side wl_buffer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All of the wl_buffer "factory interfaces" are not managed by wlr_compositor,
 | 
				
			||||||
 | 
					 * but we still need to know some extra information beyond the wl_resource
 | 
				
			||||||
 | 
					 * handle. This information is retrieved by the callbacks specified in
 | 
				
			||||||
 | 
					 * wlr_compositor_buffer_impl.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If you are using wlr_renderer, you do not need to worry about this type, as
 | 
				
			||||||
 | 
					 * wlr_renderer handles the buffer factory interfaces and the callbacks, but
 | 
				
			||||||
 | 
					 * you must call wlr_renderer_set_compositor to set this up.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_buffer {
 | 
				
			||||||
 | 
						struct wl_resource *resource;
 | 
				
			||||||
 | 
						size_t ref_cnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * This should contain the protocol name of this buffer, used for some
 | 
				
			||||||
 | 
						 * protocol conformance checks (e.g. "wl_shm"). As a special case,
 | 
				
			||||||
 | 
						 * buffers created with the EGL extension "EGL_WL_bind_wayland_display"
 | 
				
			||||||
 | 
						 * will be called "egl", regardless of what the underlying protocol is
 | 
				
			||||||
 | 
						 * called (i.e. NOT "wl_drm"). This should point to statically
 | 
				
			||||||
 | 
						 * allocated memory.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						const char *protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * The size of the buffer in buffer coordinates.
 | 
				
			||||||
 | 
						 * i.e. no scaling, cropping, or transforms applied.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						int32_t width;
 | 
				
			||||||
 | 
						int32_t height;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * See struct wlr_buffer
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_compositor_buffer_impl {
 | 
				
			||||||
 | 
						struct wlr_buffer *(*create)(void *data, struct wlr_buffer *buf,
 | 
				
			||||||
 | 
							pixman_region32_t *damage, struct wl_resource *res);
 | 
				
			||||||
 | 
						struct wlr_buffer *(*ref)(struct wlr_buffer *buf);
 | 
				
			||||||
 | 
						void (*unref)(struct wlr_buffer *buf);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Implementation of the wl_compositor global.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is responsible for creating wl_surfaces and wl_regions.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The wlr_compositor's lifetime to tied to the lifetime of the wl_display
 | 
				
			||||||
 | 
					 * it was created with, meaning that calling wl_display_destroy will destroy
 | 
				
			||||||
 | 
					 * the wlr_compositor. There is no way to destroy it earlier than this,
 | 
				
			||||||
 | 
					 * as clients can not be expected to handle this being removed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Is is an error to create two wlr_compositors for the same wl_display or
 | 
				
			||||||
 | 
					 * otherwise advertise a second wl_compositor global on it.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_compositor {
 | 
					struct wlr_compositor {
 | 
				
			||||||
	struct wl_display *display;
 | 
						struct wl_display *display;
 | 
				
			||||||
	struct wl_global *global;
 | 
						struct wl_global *global;
 | 
				
			||||||
	struct wlr_renderer *renderer;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t ids;
 | 
						uint32_t ids;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const struct wlr_compositor_buffer_impl *buffer_impl;
 | 
				
			||||||
 | 
						void *buffer_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		struct wl_signal new_surface;
 | 
							struct wl_signal new_surface;
 | 
				
			||||||
		struct wl_signal new_surface_2;
 | 
							struct wl_signal new_surface_2;
 | 
				
			||||||
| 
						 | 
					@ -32,6 +91,11 @@ struct wlr_compositor {
 | 
				
			||||||
	struct wl_listener display_destroy;
 | 
						struct wl_listener display_destroy;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_compositor_new_state_args {
 | 
				
			||||||
 | 
						struct wlr_commit *old;
 | 
				
			||||||
 | 
						struct wlr_commit *new;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_surface_2 {
 | 
					struct wlr_surface_2 {
 | 
				
			||||||
	struct wl_resource *resource;
 | 
						struct wl_resource *resource;
 | 
				
			||||||
	struct wlr_compositor *compositor;
 | 
						struct wlr_compositor *compositor;
 | 
				
			||||||
| 
						 | 
					@ -39,13 +103,13 @@ struct wlr_surface_2 {
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * This should contain the name of the protocol to prevent conflicts.
 | 
						 * This should contain the name of the protocol to prevent conflicts.
 | 
				
			||||||
	 * e.g. "xdg_toplevel".
 | 
						 * e.g. "xdg_toplevel".
 | 
				
			||||||
	 * Also, it should point to statically allocated memory.
 | 
						 * This should point to statically allocated memory.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	const char *role_name;
 | 
						const char *role_name;
 | 
				
			||||||
	void *role_data;
 | 
						void *role_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_list committed;
 | 
						struct wl_list committed; // struct wlr_commit.link
 | 
				
			||||||
	struct wl_list frame_callbacks;
 | 
						struct wl_list frame_callbacks; // struct wl_resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		struct wl_signal commit;
 | 
							struct wl_signal commit;
 | 
				
			||||||
| 
						 | 
					@ -56,8 +120,6 @@ struct wlr_surface_2 {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * wlr_commit
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * A wlr_commit is a description for a "coherent presentation" of a surface's
 | 
					 * A wlr_commit is a description for a "coherent presentation" of a surface's
 | 
				
			||||||
 * contents, or could also be thought of as a "snaphot" of the surface at
 | 
					 * contents, or could also be thought of as a "snaphot" of the surface at
 | 
				
			||||||
 * commit time. It should contain all of the information to correctly display
 | 
					 * commit time. It should contain all of the information to correctly display
 | 
				
			||||||
| 
						 | 
					@ -76,38 +138,59 @@ struct wlr_surface_2 {
 | 
				
			||||||
 * For a surface, there will always be exactly 1 pending commit for a surface.
 | 
					 * For a surface, there will always be exactly 1 pending commit for a surface.
 | 
				
			||||||
 *   see wlr_surface_get_pending
 | 
					 *   see wlr_surface_get_pending
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Excluding the time when a before the first complete commit is ready, there
 | 
					 * Excluding the time before the first complete commit is ready, there will
 | 
				
			||||||
 * will always be at least 1 complete commit for a surface. The latest complete
 | 
					 * always be at least 1 complete commit for a surface. The latest complete
 | 
				
			||||||
 * commit is called the current commit.
 | 
					 * commit is called the current commit.
 | 
				
			||||||
 *   see wlr_surface_get_commit
 | 
					 *   see wlr_surface_get_commit
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * wlr_commits are reference counted. If you wish to save the contents of a
 | 
					 * wlr_commits are reference counted. If you wish to save the contents of a
 | 
				
			||||||
 * commit for future use, simply do not unreference the commit. A referenced
 | 
					 * commit for future use, simply do not unreference the commit.
 | 
				
			||||||
 * wlr_commit will even persist after the surface is destroyed, which can be
 | 
					 | 
				
			||||||
 * useful for fade-out animations. Any extensions to wlr_surface should be
 | 
					 | 
				
			||||||
 * prepared for the associated wlr_surface to not be available.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Upon commit destruction, several actions may be performed on objects which
 | 
					 * Upon commit destruction, several actions may be performed on objects which
 | 
				
			||||||
 * will affect clients. For example, wl_buffer.release may be called for the
 | 
					 * will affect clients. For example, wl_buffer.release may be called for the
 | 
				
			||||||
 * attached buffer. Holding onto too many commits for too long may cause
 | 
					 * attached buffer. Holding onto too many commits for too long may cause
 | 
				
			||||||
 * resource starvation in clients, so care should be taken to unreference
 | 
					 * resource starvation in clients, so care should be taken to unreference
 | 
				
			||||||
 * commits as soon as they're no longer needed.
 | 
					 * commits as soon as they're no longer needed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Inhibitiors:
 | 
				
			||||||
 | 
					 * -----------
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Each commit has a counter of inhibitors, which means that the commit is
 | 
				
			||||||
 | 
					 * being prevented from becoming "complete". The intended use-case is for
 | 
				
			||||||
 | 
					 * wl_subsurfaces preventing themselves from being presented until their
 | 
				
			||||||
 | 
					 * parent has been commited, and wp_linux_explicit_synchronization from
 | 
				
			||||||
 | 
					 * being presented until a fence is signalled.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Inhibitors don't have any effect on commits which are already complete.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Orphaned Commits:
 | 
				
			||||||
 | 
					 * ----------------
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * A commit will stay valid even after the associated surface has been
 | 
				
			||||||
 | 
					 * destroyed by the client. Such a commit is called an orphaned commit.
 | 
				
			||||||
 | 
					 * Pending commits can never be orphaned, as wl_surface.commit can never be
 | 
				
			||||||
 | 
					 * called on them.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This can be useful for fade-out animations of a client's surface.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Any extension to wlr_commit should be prepared for the associated
 | 
				
			||||||
 | 
					 * wlr_surface to not be available.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct wlr_commit {
 | 
					struct wlr_commit {
 | 
				
			||||||
	struct wl_list link;
 | 
						struct wl_list link;
 | 
				
			||||||
 | 
						struct wlr_compositor *compositor;
 | 
				
			||||||
	struct wlr_surface_2 *surface;
 | 
						struct wlr_surface_2 *surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If the user has called wl_surface.commit
 | 
						// If the client has called wl_surface.commit
 | 
				
			||||||
	bool committed;
 | 
						bool committed;
 | 
				
			||||||
	// See wlr_commit_inhibit
 | 
						// See wlr_commit_inhibit
 | 
				
			||||||
	size_t inhibit;
 | 
						size_t inhibit;
 | 
				
			||||||
	size_t ref_cnt;
 | 
						size_t ref_cnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// wl_surface.attach
 | 
						// wl_surface.attach
 | 
				
			||||||
 | 
						struct wlr_buffer *buffer;
 | 
				
			||||||
	struct wl_resource *buffer_resource;
 | 
						struct wl_resource *buffer_resource;
 | 
				
			||||||
	int32_t sx, sy;
 | 
						int32_t sx, sy;
 | 
				
			||||||
	// wl_surface.damage
 | 
					 | 
				
			||||||
	pixman_region32_t surface_damage;
 | 
					 | 
				
			||||||
	// wl_surface.frame
 | 
						// wl_surface.frame
 | 
				
			||||||
	struct wl_list frame_callbacks;
 | 
						struct wl_list frame_callbacks;
 | 
				
			||||||
	// wl_surface.set_opaque_region
 | 
						// wl_surface.set_opaque_region
 | 
				
			||||||
| 
						 | 
					@ -119,37 +202,83 @@ struct wlr_commit {
 | 
				
			||||||
	// wl_surface.set_buffer_scale
 | 
						// wl_surface.set_buffer_scale
 | 
				
			||||||
	int32_t scale;
 | 
						int32_t scale;
 | 
				
			||||||
	// wl_surface.damage_buffer
 | 
						// wl_surface.damage_buffer
 | 
				
			||||||
	pixman_region32_t buffer_damage;
 | 
						pixman_region32_t damage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size_t state_len;
 | 
						size_t state_len;
 | 
				
			||||||
	void **state;
 | 
						void **state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * arg: struct wlr_commit *this
 | 
				
			||||||
 | 
							 * The client called wl_surface.commit.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		struct wl_signal commit;
 | 
							struct wl_signal commit;
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * arg: struct wlr_commit *this
 | 
				
			||||||
 | 
							 * The commit has transitioned to the complete state, and is
 | 
				
			||||||
 | 
							 * now ready to be presented.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		struct wl_signal complete;
 | 
							struct wl_signal complete;
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * arg: struct wlr_commit *this
 | 
				
			||||||
 | 
							 * The wlr_commit has been destroyed.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_compositor_new_state_args {
 | 
					struct wlr_compositor *wlr_compositor_create(struct wl_display *display);
 | 
				
			||||||
	struct wlr_commit *old;
 | 
					void wlr_compositor_set_buffer_impl(struct wlr_compositor *comp,
 | 
				
			||||||
	struct wlr_commit *new;
 | 
							void *data, const struct wlr_compositor_buffer_impl *impl);
 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wlr_compositor *wlr_compositor_create(struct wl_display *display,
 | 
					 | 
				
			||||||
	struct wlr_renderer *renderer);
 | 
					 | 
				
			||||||
uint32_t wlr_compositor_register(struct wlr_compositor *compositor);
 | 
					uint32_t wlr_compositor_register(struct wlr_compositor *compositor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_surface_2 *wlr_surface_from_resource_2(struct wl_resource *resource);
 | 
					struct wlr_surface_2 *wlr_surface_from_resource_2(struct wl_resource *resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Get the latest complete commit for a surface.
 | 
				
			||||||
 | 
					 * This increases the reference count of the commit.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns NULL if there is no complete commit yet.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_commit *wlr_surface_get_commit(struct wlr_surface_2 *surface);
 | 
					struct wlr_commit *wlr_surface_get_commit(struct wlr_surface_2 *surface);
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Get the current pending commit for a surface.
 | 
				
			||||||
 | 
					 * This DOES NOT increase the reference count of the commit.
 | 
				
			||||||
 | 
					 * This is not intended to be used outside of extensions to wlr_commit.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This will never fail.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_commit *wlr_surface_get_pending(struct wlr_surface_2 *surface);
 | 
					struct wlr_commit *wlr_surface_get_pending(struct wlr_surface_2 *surface);
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Gets the latest committed or complete commit.
 | 
				
			||||||
 | 
					 * This increases the reference count of the commit.
 | 
				
			||||||
 | 
					 * This is not intended to be used outside of extensions to wlr_commit.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If you are looking for the latest complete commit, use
 | 
				
			||||||
 | 
					 * wlr_surface_get_commit instead.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns NULL if there is no committed/complete commit yet.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_commit *wlr_surface_get_latest(struct wlr_surface_2 *surface);
 | 
					struct wlr_commit *wlr_surface_get_latest(struct wlr_surface_2 *surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_surface_send_enter_2(struct wlr_surface_2 *surf, struct wlr_output *output);
 | 
					void wlr_surface_send_enter_2(struct wlr_surface_2 *surf, struct wlr_output *output);
 | 
				
			||||||
void wlr_surface_send_leave_2(struct wlr_surface_2 *surf, struct wlr_output *output);
 | 
					void wlr_surface_send_leave_2(struct wlr_surface_2 *surf, struct wlr_output *output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Increases the reference count of a commit.
 | 
				
			||||||
 | 
					 * commit must be non-null.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * commit is returned from this function as a convinience to do
 | 
				
			||||||
 | 
					 * `struct wlr_commit *saved = wlr_commit_ref(commit);`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_commit *wlr_commit_ref(struct wlr_commit *commit);
 | 
					struct wlr_commit *wlr_commit_ref(struct wlr_commit *commit);
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Decreases the reference count for a commit.
 | 
				
			||||||
 | 
					 * commit must be non-null and have a positive reference count.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The commit is not necessarily freed immediately when the reference count
 | 
				
			||||||
 | 
					 * reaches zero, depending on its state and position in the commit queue.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
void wlr_commit_unref(struct wlr_commit *commit);
 | 
					void wlr_commit_unref(struct wlr_commit *commit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wlr_commit_is_complete(struct wlr_commit *c);
 | 
					bool wlr_commit_is_complete(struct wlr_commit *c);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										34
									
								
								meson.build
									
										
									
									
									
								
							
							
						
						
									
										34
									
								
								meson.build
									
										
									
									
									
								
							| 
						 | 
					@ -169,7 +169,7 @@ summary = [
 | 
				
			||||||
message('\n'.join(summary))
 | 
					message('\n'.join(summary))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
executable('test-server', 'test-server.c',
 | 
					executable('test-server', 'test-server.c',
 | 
				
			||||||
	dependencies: wlroots)
 | 
						dependencies: [wlroots, gbm])
 | 
				
			||||||
executable('test-client', 'test-client.c',
 | 
					executable('test-client', 'test-client.c',
 | 
				
			||||||
	dependencies: wayland_client)
 | 
						dependencies: wayland_client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -185,35 +185,3 @@ pkgconfig.generate(
 | 
				
			||||||
	description: 'Wayland compositor library',
 | 
						description: 'Wayland compositor library',
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
git = find_program('git', required: false)
 | 
					 | 
				
			||||||
if git.found()
 | 
					 | 
				
			||||||
	all_files = run_command(
 | 
					 | 
				
			||||||
		git,
 | 
					 | 
				
			||||||
		'--git-dir=@0@/.git'.format(meson.current_source_dir()),
 | 
					 | 
				
			||||||
		'ls-files',
 | 
					 | 
				
			||||||
		':/*.[ch]',
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	all_files = files(all_files.stdout().split())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	etags = find_program('etags', required: false)
 | 
					 | 
				
			||||||
	if etags.found() and all_files.length() > 0
 | 
					 | 
				
			||||||
		custom_target(
 | 
					 | 
				
			||||||
			'etags',
 | 
					 | 
				
			||||||
			build_by_default: true,
 | 
					 | 
				
			||||||
			input: all_files,
 | 
					 | 
				
			||||||
			output: 'TAGS',
 | 
					 | 
				
			||||||
			command: [etags, '-o', '@OUTPUT@', '@INPUT@'],
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
	endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctags = find_program('ctags', required: false)
 | 
					 | 
				
			||||||
	if ctags.found() and all_files.length() > 0
 | 
					 | 
				
			||||||
		custom_target(
 | 
					 | 
				
			||||||
			'ctags',
 | 
					 | 
				
			||||||
			build_by_default: true,
 | 
					 | 
				
			||||||
			input: all_files,
 | 
					 | 
				
			||||||
			output: 'tags',
 | 
					 | 
				
			||||||
			command: [ctags, '-f', '@OUTPUT@', '@INPUT@'],
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
	endif
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,11 @@
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <pixman.h>
 | 
				
			||||||
#include <wlr/render/gles2.h>
 | 
					#include <wlr/render/gles2.h>
 | 
				
			||||||
#include <wlr/render/interface.h>
 | 
					#include <wlr/render/interface.h>
 | 
				
			||||||
#include <wlr/render/wlr_renderer.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_compositor.h>
 | 
				
			||||||
#include <wlr/types/wlr_linux_dmabuf_v1.h>
 | 
					#include <wlr/types/wlr_linux_dmabuf_v1.h>
 | 
				
			||||||
#include <wlr/types/wlr_matrix.h>
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
| 
						 | 
					@ -147,15 +149,232 @@ bool wlr_renderer_format_supported(struct wlr_renderer *r,
 | 
				
			||||||
	return r->impl->format_supported(r, fmt);
 | 
						return r->impl->format_supported(r, fmt);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_renderer_init_wl_display(struct wlr_renderer *r,
 | 
					struct buffer {
 | 
				
			||||||
		struct wl_display *wl_display) {
 | 
						struct wlr_buffer base;
 | 
				
			||||||
	if (wl_display_init_shm(wl_display)) {
 | 
						struct wl_list link;
 | 
				
			||||||
		wlr_log(WLR_ERROR, "Failed to initialize shm");
 | 
					
 | 
				
			||||||
 | 
						bool released;
 | 
				
			||||||
 | 
						struct wlr_texture *texture;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wl_listener resource_destroy;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void buffer_resource_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct buffer *buf = wl_container_of(listener, buf, resource_destroy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buf->base.resource = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * At this point, if the wl_buffer comes from a dmabuf-based buffer, we
 | 
				
			||||||
 | 
						 * still haven't released it (i.e. we'll read it in the future) but the
 | 
				
			||||||
 | 
						 * client destroyed it. Reading the texture itself should be fine
 | 
				
			||||||
 | 
						 * because we still hold a reference to the dmabuf via the texture.
 | 
				
			||||||
 | 
						 * However the client could decide to re-use the same dmabuf for
 | 
				
			||||||
 | 
						 * something else, in which case we'll read garbage. We decide to
 | 
				
			||||||
 | 
						 * accept this risk.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct wlr_buffer *create_buffer(struct wlr_renderer *renderer,
 | 
				
			||||||
 | 
							struct wl_resource *res) {
 | 
				
			||||||
 | 
						struct buffer *buf = calloc(1, sizeof(*buf));
 | 
				
			||||||
 | 
						if (!buf) {
 | 
				
			||||||
 | 
							wlr_log_errno(WLR_ERROR, "Allocation failed");
 | 
				
			||||||
 | 
							wl_resource_post_no_memory(res);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wl_shm_buffer *shm = wl_shm_buffer_get(res);
 | 
				
			||||||
 | 
						if (shm) {
 | 
				
			||||||
 | 
							enum wl_shm_format fmt = wl_shm_buffer_get_format(shm);
 | 
				
			||||||
 | 
							int32_t stride = wl_shm_buffer_get_stride(shm);
 | 
				
			||||||
 | 
							int32_t width = wl_shm_buffer_get_width(shm);
 | 
				
			||||||
 | 
							int32_t height = wl_shm_buffer_get_height(shm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							wl_shm_buffer_begin_access(shm);
 | 
				
			||||||
 | 
							void *data = wl_shm_buffer_get_data(shm);
 | 
				
			||||||
 | 
							buf->texture = wlr_texture_from_pixels(renderer, fmt, stride,
 | 
				
			||||||
 | 
								width, height, data);
 | 
				
			||||||
 | 
							wl_shm_buffer_end_access(shm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * We have uploaded the data, we don't need to access the
 | 
				
			||||||
 | 
							 * wl_buffer anymore
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							wl_buffer_send_release(res);
 | 
				
			||||||
 | 
							buf->released = true;
 | 
				
			||||||
 | 
							buf->base.protocol = "wl_shm";
 | 
				
			||||||
 | 
						} else if (wlr_renderer_resource_is_wl_drm_buffer(renderer, res)) {
 | 
				
			||||||
 | 
							buf->texture = wlr_texture_from_wl_drm(renderer, res);
 | 
				
			||||||
 | 
							buf->base.protocol = "egl";
 | 
				
			||||||
 | 
						} else if (wlr_dmabuf_v1_resource_is_buffer(res)) {
 | 
				
			||||||
 | 
							struct wlr_dmabuf_v1_buffer *dmabuf =
 | 
				
			||||||
 | 
								wlr_dmabuf_v1_buffer_from_buffer_resource(res);
 | 
				
			||||||
 | 
							buf->texture = wlr_texture_from_dmabuf(renderer, &dmabuf->attributes);
 | 
				
			||||||
 | 
							buf->base.protocol = "zwp_linux_dmabuf_v1";
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							wlr_log(WLR_ERROR, "Cannot upload texture: unknown buffer type");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Instead of just logging the error, also disconnect the client with a
 | 
				
			||||||
 | 
							// fatal protocol error so that it's clear something went wrong.
 | 
				
			||||||
 | 
							wl_resource_post_error(res, 0, "unknown buffer type");
 | 
				
			||||||
 | 
							free(buf);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!buf->texture) {
 | 
				
			||||||
 | 
							wlr_log(WLR_ERROR, "Failed to create texture");
 | 
				
			||||||
 | 
							wl_resource_post_error(res, 0, "failed to use buffer");
 | 
				
			||||||
 | 
							free(buf);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int width, height;
 | 
				
			||||||
 | 
						wlr_texture_get_size(buf->texture, &width, &height);
 | 
				
			||||||
 | 
						buf->base.width = width;
 | 
				
			||||||
 | 
						buf->base.height = height;
 | 
				
			||||||
 | 
						buf->base.ref_cnt = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &buf->base;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct wlr_buffer *buffer_ref(struct wlr_buffer *buffer) {
 | 
				
			||||||
 | 
						assert(buffer);
 | 
				
			||||||
 | 
						++buffer->ref_cnt;
 | 
				
			||||||
 | 
						return buffer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void buffer_unref(struct wlr_buffer *buffer_base) {
 | 
				
			||||||
 | 
						struct buffer *buffer = wl_container_of(buffer_base, buffer, base);
 | 
				
			||||||
 | 
						assert(buffer->base.ref_cnt > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (--buffer->base.ref_cnt > 0) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (buffer->base.resource) {
 | 
				
			||||||
 | 
							if (!buffer->released) {
 | 
				
			||||||
 | 
								wl_buffer_send_release(buffer->base.resource);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							wl_list_remove(&buffer->resource_destroy.link);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_texture_destroy(buffer->texture);
 | 
				
			||||||
 | 
						free(buffer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct wlr_buffer *buffer_create(void *userdata,
 | 
				
			||||||
 | 
							struct wlr_buffer *buffer_base, pixman_region32_t *buffer_damage,
 | 
				
			||||||
 | 
							struct wl_resource *res) {
 | 
				
			||||||
 | 
						struct wlr_renderer *renderer = userdata;
 | 
				
			||||||
 | 
						struct buffer *buffer = wl_container_of(buffer_base, buffer, base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!buffer) {
 | 
				
			||||||
 | 
							return create_buffer(renderer, res);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * The old buffer is still being used somewhere else, so we cannot
 | 
				
			||||||
 | 
						 * change/reuse it.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (buffer->base.ref_cnt != 1) {
 | 
				
			||||||
 | 
							buffer_unref(&buffer->base);
 | 
				
			||||||
 | 
							return create_buffer(renderer, res);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Any kind of buffer sharing only happens with wl_shm.
 | 
				
			||||||
 | 
						 * dmabuf-based textures are cheap to create and aren't modifiable.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct wl_shm_buffer *old_shm = wl_shm_buffer_get(buffer->base.resource);
 | 
				
			||||||
 | 
						struct wl_shm_buffer *new_shm = wl_shm_buffer_get(res);
 | 
				
			||||||
 | 
						if (!old_shm || !new_shm) {
 | 
				
			||||||
 | 
							buffer_unref(&buffer->base);
 | 
				
			||||||
 | 
							return create_buffer(renderer, res);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * We can't change the shm format.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						enum wl_shm_format old_fmt = wl_shm_buffer_get_format(old_shm);
 | 
				
			||||||
 | 
						enum wl_shm_format new_fmt = wl_shm_buffer_get_format(new_shm);
 | 
				
			||||||
 | 
						if (old_fmt != new_fmt) {
 | 
				
			||||||
 | 
							buffer_unref(&buffer->base);
 | 
				
			||||||
 | 
							return create_buffer(renderer, res);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * We can't change the dimensions.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						int32_t stride = wl_shm_buffer_get_stride(new_shm);
 | 
				
			||||||
 | 
						int32_t width = wl_shm_buffer_get_width(new_shm);
 | 
				
			||||||
 | 
						int32_t height = wl_shm_buffer_get_height(new_shm);
 | 
				
			||||||
 | 
						int old_width, old_height;
 | 
				
			||||||
 | 
						wlr_texture_get_size(buffer->texture, &old_width, &old_height);
 | 
				
			||||||
 | 
						if (width != old_width || height != old_height) {
 | 
				
			||||||
 | 
							buffer_unref(&buffer->base);
 | 
				
			||||||
 | 
							return create_buffer(renderer, res);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_shm_buffer_begin_access(new_shm);
 | 
				
			||||||
 | 
						void *data = wl_shm_buffer_get_data(new_shm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Apply damage to buffer.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						pixman_region32_t damage;
 | 
				
			||||||
 | 
						pixman_region32_init_rect(&damage, 0, 0, width, height);
 | 
				
			||||||
 | 
						pixman_region32_intersect(&damage, &damage, buffer_damage);
 | 
				
			||||||
 | 
						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(buffer->texture, stride,
 | 
				
			||||||
 | 
									r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1,
 | 
				
			||||||
 | 
									r->x1, r->y1, data)) {
 | 
				
			||||||
 | 
								wlr_log(WLR_ERROR, "Failed to write pixels");
 | 
				
			||||||
 | 
								wl_resource_post_error(res, 0, "failed to use buffer");
 | 
				
			||||||
 | 
								buffer_unref(&buffer->base);
 | 
				
			||||||
 | 
								wl_shm_buffer_end_access(new_shm);
 | 
				
			||||||
 | 
								pixman_region32_fini(&damage);
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_shm_buffer_end_access(new_shm);
 | 
				
			||||||
 | 
						pixman_region32_fini(&damage);
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * We've copied the data into a local GPU buffer, so we don't need to
 | 
				
			||||||
 | 
						 * hold onto the wl_buffer anymore.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						wl_buffer_send_release(res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_list_remove(&buffer->resource_destroy.link);
 | 
				
			||||||
 | 
						wl_resource_add_destroy_listener(res, &buffer->resource_destroy);
 | 
				
			||||||
 | 
						buffer->resource_destroy.notify = buffer_resource_destroy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buffer->base.resource = res;
 | 
				
			||||||
 | 
						buffer->released = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &buffer->base;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct wlr_compositor_buffer_impl buffer_impl = {
 | 
				
			||||||
 | 
						.create = buffer_create,
 | 
				
			||||||
 | 
						.ref = buffer_ref,
 | 
				
			||||||
 | 
						.unref = buffer_unref,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_renderer_set_compositor(struct wlr_renderer *renderer,
 | 
				
			||||||
 | 
							struct wlr_compositor *comp) {
 | 
				
			||||||
 | 
						assert(renderer);
 | 
				
			||||||
 | 
						assert(comp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wl_display *display = comp->display;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size_t len;
 | 
						size_t len;
 | 
				
			||||||
	const enum wl_shm_format *formats = wlr_renderer_get_formats(r, &len);
 | 
						const enum wl_shm_format *formats = wlr_renderer_get_formats(renderer, &len);
 | 
				
			||||||
	if (formats == NULL) {
 | 
						if (formats == NULL) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "Failed to initialize shm: cannot get formats");
 | 
							wlr_log(WLR_ERROR, "Failed to initialize shm: cannot get formats");
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -165,17 +384,35 @@ void wlr_renderer_init_wl_display(struct wlr_renderer *r,
 | 
				
			||||||
		// These formats are already added by default
 | 
							// These formats are already added by default
 | 
				
			||||||
		if (formats[i] != WL_SHM_FORMAT_ARGB8888 &&
 | 
							if (formats[i] != WL_SHM_FORMAT_ARGB8888 &&
 | 
				
			||||||
				formats[i] != WL_SHM_FORMAT_XRGB8888) {
 | 
									formats[i] != WL_SHM_FORMAT_XRGB8888) {
 | 
				
			||||||
			wl_display_add_shm_format(wl_display, formats[i]);
 | 
								wl_display_add_shm_format(display, formats[i]);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (r->impl->texture_from_dmabuf) {
 | 
						if (wl_display_init_shm(display)) {
 | 
				
			||||||
		wlr_linux_dmabuf_v1_create(wl_display, r);
 | 
							wlr_log(WLR_ERROR, "Failed to initialize shm");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (r->impl->init_wl_display) {
 | 
						if (renderer->impl->texture_from_dmabuf) {
 | 
				
			||||||
		r->impl->init_wl_display(r, wl_display);
 | 
							wlr_linux_dmabuf_v1_create(display, renderer);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (renderer->impl->init_wl_display) {
 | 
				
			||||||
 | 
							renderer->impl->init_wl_display(renderer, display);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_compositor_set_buffer_impl(comp, renderer, &buffer_impl);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_texture *wlr_commit_get_texture(struct wlr_commit *commit) {
 | 
				
			||||||
 | 
						assert(commit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (commit->buffer) {
 | 
				
			||||||
 | 
							struct buffer *buffer = wl_container_of(commit->buffer, buffer, base);
 | 
				
			||||||
 | 
							return buffer->texture;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_renderer *wlr_renderer_autocreate(struct wlr_egl *egl,
 | 
					struct wlr_renderer *wlr_renderer_autocreate(struct wlr_egl *egl,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,14 @@
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <gbm.h>
 | 
				
			||||||
#include <signal.h>
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <wlr/types/wlr_compositor.h>
 | 
					#include <wlr/types/wlr_compositor.h>
 | 
				
			||||||
#include <wlr/types/wlr_subcompositor.h>
 | 
					#include <wlr/types/wlr_subcompositor.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_texture.h>
 | 
				
			||||||
 | 
					#include <wlr/render/egl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wl_display *display;
 | 
					struct wl_display *display;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,12 +24,26 @@ int main(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	signal(SIGINT, sigint);
 | 
						signal(SIGINT, sigint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_compositor *comp = wlr_compositor_create(display, NULL);
 | 
						int fd = open("/dev/dri/renderD128", O_RDWR);
 | 
				
			||||||
 | 
						struct gbm_device *gbm = gbm_create_device(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_egl egl = {0};
 | 
				
			||||||
 | 
						struct wlr_renderer *renderer = wlr_renderer_autocreate(&egl,
 | 
				
			||||||
 | 
							EGL_PLATFORM_GBM_MESA, gbm, NULL, GBM_FORMAT_XRGB8888);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_compositor *comp = wlr_compositor_create(display);
 | 
				
			||||||
	struct wlr_subcompositor *subcomp = wlr_subcompositor_create(comp);
 | 
						struct wlr_subcompositor *subcomp = wlr_subcompositor_create(comp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_renderer_set_compositor(renderer, comp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	(void)subcomp;
 | 
						(void)subcomp;
 | 
				
			||||||
	wl_display_run(display);
 | 
						wl_display_run(display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_renderer_destroy(renderer);
 | 
				
			||||||
 | 
						wlr_egl_finish(&egl);
 | 
				
			||||||
 | 
						gbm_device_destroy(gbm);
 | 
				
			||||||
 | 
						close(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_display_destroy_clients(display);
 | 
						wl_display_destroy_clients(display);
 | 
				
			||||||
	wl_display_destroy(display);
 | 
						wl_display_destroy(display);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,7 +24,6 @@ lib_wlr_types = static_library(
 | 
				
			||||||
		#'xdg_shell/wlr_xdg_surface.c',
 | 
							#'xdg_shell/wlr_xdg_surface.c',
 | 
				
			||||||
		#'xdg_shell/wlr_xdg_toplevel.c',
 | 
							#'xdg_shell/wlr_xdg_toplevel.c',
 | 
				
			||||||
		'wlr_box.c',
 | 
							'wlr_box.c',
 | 
				
			||||||
		'wlr_buffer.c',
 | 
					 | 
				
			||||||
		'wlr_compositor.c',
 | 
							'wlr_compositor.c',
 | 
				
			||||||
		'wlr_subcompositor.c',
 | 
							'wlr_subcompositor.c',
 | 
				
			||||||
		#'wlr_cursor.c',
 | 
							#'wlr_cursor.c',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,205 +0,0 @@
 | 
				
			||||||
#include <assert.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <wlr/render/wlr_renderer.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_buffer.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_linux_dmabuf_v1.h>
 | 
					 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool wlr_resource_is_buffer(struct wl_resource *resource) {
 | 
					 | 
				
			||||||
	return strcmp(wl_resource_get_class(resource), wl_buffer_interface.name) == 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool wlr_buffer_get_resource_size(struct wl_resource *resource,
 | 
					 | 
				
			||||||
		struct wlr_renderer *renderer, int *width, int *height) {
 | 
					 | 
				
			||||||
	assert(wlr_resource_is_buffer(resource));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wl_shm_buffer *shm_buf = wl_shm_buffer_get(resource);
 | 
					 | 
				
			||||||
	if (shm_buf != NULL) {
 | 
					 | 
				
			||||||
		*width = wl_shm_buffer_get_width(shm_buf);
 | 
					 | 
				
			||||||
		*height = wl_shm_buffer_get_height(shm_buf);
 | 
					 | 
				
			||||||
	} else if (wlr_renderer_resource_is_wl_drm_buffer(renderer,
 | 
					 | 
				
			||||||
			resource)) {
 | 
					 | 
				
			||||||
		wlr_renderer_wl_drm_buffer_get_size(renderer, resource,
 | 
					 | 
				
			||||||
			width, height);
 | 
					 | 
				
			||||||
	} else if (wlr_dmabuf_v1_resource_is_buffer(resource)) {
 | 
					 | 
				
			||||||
		struct wlr_dmabuf_v1_buffer *dmabuf =
 | 
					 | 
				
			||||||
			wlr_dmabuf_v1_buffer_from_buffer_resource(resource);
 | 
					 | 
				
			||||||
		*width = dmabuf->attributes.width;
 | 
					 | 
				
			||||||
		*height = dmabuf->attributes.height;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		*width = *height = 0;
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void buffer_resource_handle_destroy(struct wl_listener *listener,
 | 
					 | 
				
			||||||
		void *data) {
 | 
					 | 
				
			||||||
	struct wlr_buffer *buffer =
 | 
					 | 
				
			||||||
		wl_container_of(listener, buffer, resource_destroy);
 | 
					 | 
				
			||||||
	wl_list_remove(&buffer->resource_destroy.link);
 | 
					 | 
				
			||||||
	wl_list_init(&buffer->resource_destroy.link);
 | 
					 | 
				
			||||||
	buffer->resource = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// At this point, if the wl_buffer comes from linux-dmabuf or wl_drm, we
 | 
					 | 
				
			||||||
	// still haven't released it (ie. we'll read it in the future) but the
 | 
					 | 
				
			||||||
	// client destroyed it. Reading the texture itself should be fine because
 | 
					 | 
				
			||||||
	// we still hold a reference to the DMA-BUF via the texture. However the
 | 
					 | 
				
			||||||
	// client could decide to re-use the same DMA-BUF for something else, in
 | 
					 | 
				
			||||||
	// which case we'll read garbage. We decide to accept this risk.
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer,
 | 
					 | 
				
			||||||
		struct wl_resource *resource) {
 | 
					 | 
				
			||||||
	assert(wlr_resource_is_buffer(resource));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_texture *texture = NULL;
 | 
					 | 
				
			||||||
	bool released = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wl_shm_buffer *shm_buf = wl_shm_buffer_get(resource);
 | 
					 | 
				
			||||||
	if (shm_buf != NULL) {
 | 
					 | 
				
			||||||
		enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buf);
 | 
					 | 
				
			||||||
		int32_t stride = wl_shm_buffer_get_stride(shm_buf);
 | 
					 | 
				
			||||||
		int32_t width = wl_shm_buffer_get_width(shm_buf);
 | 
					 | 
				
			||||||
		int32_t height = wl_shm_buffer_get_height(shm_buf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		wl_shm_buffer_begin_access(shm_buf);
 | 
					 | 
				
			||||||
		void *data = wl_shm_buffer_get_data(shm_buf);
 | 
					 | 
				
			||||||
		texture = wlr_texture_from_pixels(renderer, fmt, stride,
 | 
					 | 
				
			||||||
			width, height, data);
 | 
					 | 
				
			||||||
		wl_shm_buffer_end_access(shm_buf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// We have uploaded the data, we don't need to access the wl_buffer
 | 
					 | 
				
			||||||
		// anymore
 | 
					 | 
				
			||||||
		wl_buffer_send_release(resource);
 | 
					 | 
				
			||||||
		released = true;
 | 
					 | 
				
			||||||
	} else if (wlr_renderer_resource_is_wl_drm_buffer(renderer, resource)) {
 | 
					 | 
				
			||||||
		texture = wlr_texture_from_wl_drm(renderer, resource);
 | 
					 | 
				
			||||||
	} else if (wlr_dmabuf_v1_resource_is_buffer(resource)) {
 | 
					 | 
				
			||||||
		struct wlr_dmabuf_v1_buffer *dmabuf =
 | 
					 | 
				
			||||||
			wlr_dmabuf_v1_buffer_from_buffer_resource(resource);
 | 
					 | 
				
			||||||
		texture = wlr_texture_from_dmabuf(renderer, &dmabuf->attributes);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// We have imported the DMA-BUF, but we need to prevent the client from
 | 
					 | 
				
			||||||
		// re-using the same DMA-BUF for the next frames, so we don't release
 | 
					 | 
				
			||||||
		// the buffer yet.
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		wlr_log(WLR_ERROR, "Cannot upload texture: unknown buffer type");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Instead of just logging the error, also disconnect the client with a
 | 
					 | 
				
			||||||
		// fatal protocol error so that it's clear something went wrong.
 | 
					 | 
				
			||||||
		wl_resource_post_error(resource, 0, "unknown buffer type");
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (texture == NULL) {
 | 
					 | 
				
			||||||
		wlr_log(WLR_ERROR, "Failed to upload texture");
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_buffer *buffer = calloc(1, sizeof(struct wlr_buffer));
 | 
					 | 
				
			||||||
	if (buffer == NULL) {
 | 
					 | 
				
			||||||
		wlr_texture_destroy(texture);
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	buffer->resource = resource;
 | 
					 | 
				
			||||||
	buffer->texture = texture;
 | 
					 | 
				
			||||||
	buffer->released = released;
 | 
					 | 
				
			||||||
	buffer->n_refs = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wl_resource_add_destroy_listener(resource, &buffer->resource_destroy);
 | 
					 | 
				
			||||||
	buffer->resource_destroy.notify = buffer_resource_handle_destroy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return buffer;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wlr_buffer *wlr_buffer_ref(struct wlr_buffer *buffer) {
 | 
					 | 
				
			||||||
	buffer->n_refs++;
 | 
					 | 
				
			||||||
	return buffer;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void wlr_buffer_unref(struct wlr_buffer *buffer) {
 | 
					 | 
				
			||||||
	if (buffer == NULL) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert(buffer->n_refs > 0);
 | 
					 | 
				
			||||||
	buffer->n_refs--;
 | 
					 | 
				
			||||||
	if (buffer->n_refs > 0) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!buffer->released && buffer->resource != NULL) {
 | 
					 | 
				
			||||||
		wl_buffer_send_release(buffer->resource);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wl_list_remove(&buffer->resource_destroy.link);
 | 
					 | 
				
			||||||
	wlr_texture_destroy(buffer->texture);
 | 
					 | 
				
			||||||
	free(buffer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wlr_buffer *wlr_buffer_apply_damage(struct wlr_buffer *buffer,
 | 
					 | 
				
			||||||
		struct wl_resource *resource, pixman_region32_t *damage) {
 | 
					 | 
				
			||||||
	assert(wlr_resource_is_buffer(resource));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (buffer->n_refs > 1) {
 | 
					 | 
				
			||||||
		// Someone else still has a reference to the buffer
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wl_shm_buffer *shm_buf = wl_shm_buffer_get(resource);
 | 
					 | 
				
			||||||
	struct wl_shm_buffer *old_shm_buf = wl_shm_buffer_get(buffer->resource);
 | 
					 | 
				
			||||||
	if (shm_buf == NULL || old_shm_buf == NULL) {
 | 
					 | 
				
			||||||
		// Uploading only damaged regions only works for wl_shm buffers and
 | 
					 | 
				
			||||||
		// mutable textures (created from wl_shm buffer)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	enum wl_shm_format new_fmt = wl_shm_buffer_get_format(shm_buf);
 | 
					 | 
				
			||||||
	enum wl_shm_format old_fmt = wl_shm_buffer_get_format(old_shm_buf);
 | 
					 | 
				
			||||||
	if (new_fmt != old_fmt) {
 | 
					 | 
				
			||||||
		// Uploading to textures can't change the format
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int32_t stride = wl_shm_buffer_get_stride(shm_buf);
 | 
					 | 
				
			||||||
	int32_t width = wl_shm_buffer_get_width(shm_buf);
 | 
					 | 
				
			||||||
	int32_t height = wl_shm_buffer_get_height(shm_buf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int32_t texture_width, texture_height;
 | 
					 | 
				
			||||||
	wlr_texture_get_size(buffer->texture, &texture_width, &texture_height);
 | 
					 | 
				
			||||||
	if (width != texture_width || height != texture_height) {
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wl_shm_buffer_begin_access(shm_buf);
 | 
					 | 
				
			||||||
	void *data = wl_shm_buffer_get_data(shm_buf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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(buffer->texture, stride,
 | 
					 | 
				
			||||||
				r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1,
 | 
					 | 
				
			||||||
				r->x1, r->y1, data)) {
 | 
					 | 
				
			||||||
			wl_shm_buffer_end_access(shm_buf);
 | 
					 | 
				
			||||||
			return NULL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wl_shm_buffer_end_access(shm_buf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// We have uploaded the data, we don't need to access the wl_buffer
 | 
					 | 
				
			||||||
	// anymore
 | 
					 | 
				
			||||||
	wl_buffer_send_release(resource);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wl_list_remove(&buffer->resource_destroy.link);
 | 
					 | 
				
			||||||
	wl_resource_add_destroy_listener(resource, &buffer->resource_destroy);
 | 
					 | 
				
			||||||
	buffer->resource_destroy.notify = buffer_resource_handle_destroy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	buffer->resource = resource;
 | 
					 | 
				
			||||||
	buffer->released = true;
 | 
					 | 
				
			||||||
	return buffer;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,22 @@ pixman_region32_t *wlr_region_from_resource(struct wl_resource *resource) {
 | 
				
			||||||
	return wl_resource_get_user_data(resource);
 | 
						return wl_resource_get_user_data(resource);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct wlr_buffer *compositor_buffer_create(struct wlr_compositor *comp,
 | 
				
			||||||
 | 
							struct wlr_buffer *old, pixman_region32_t *damage,
 | 
				
			||||||
 | 
							struct wl_resource *res) {
 | 
				
			||||||
 | 
						return comp->buffer_impl->create(comp->buffer_data, old, damage, res);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct wlr_buffer *compositor_buffer_ref(struct wlr_compositor *comp,
 | 
				
			||||||
 | 
							struct wlr_buffer *buf) {
 | 
				
			||||||
 | 
						return comp->buffer_impl->ref(buf);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void compositor_buffer_unref(struct wlr_compositor *comp,
 | 
				
			||||||
 | 
							struct wlr_buffer *buf) {
 | 
				
			||||||
 | 
						comp->buffer_impl->unref(buf);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void region_destroy(struct wl_client *client, struct wl_resource *resource) {
 | 
					static void region_destroy(struct wl_client *client, struct wl_resource *resource) {
 | 
				
			||||||
	wl_resource_destroy(resource);
 | 
						wl_resource_destroy(resource);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -70,27 +86,30 @@ static struct wlr_commit *commit_create(struct wlr_surface_2 *surf) {
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c->compositor = comp;
 | 
				
			||||||
	c->surface = surf;
 | 
						c->surface = surf;
 | 
				
			||||||
	wl_signal_init(&c->events.commit);
 | 
						wl_signal_init(&c->events.commit);
 | 
				
			||||||
	wl_signal_init(&c->events.complete);
 | 
						wl_signal_init(&c->events.complete);
 | 
				
			||||||
	wl_signal_init(&c->events.destroy);
 | 
						wl_signal_init(&c->events.destroy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pixman_region32_init(&c->surface_damage);
 | 
					 | 
				
			||||||
	wl_list_init(&c->frame_callbacks);
 | 
						wl_list_init(&c->frame_callbacks);
 | 
				
			||||||
	pixman_region32_init(&c->opaque_region);
 | 
						pixman_region32_init(&c->opaque_region);
 | 
				
			||||||
	pixman_region32_init_rect(&c->input_region,
 | 
						pixman_region32_init_rect(&c->input_region,
 | 
				
			||||||
		INT_MIN, INT_MIN, UINT_MAX, UINT_MAX);
 | 
							INT_MIN, INT_MIN, UINT_MAX, UINT_MAX);
 | 
				
			||||||
	c->scale = 1;
 | 
						c->scale = 1;
 | 
				
			||||||
	pixman_region32_init(&c->buffer_damage);
 | 
						pixman_region32_init(&c->damage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return c;
 | 
						return c;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void commit_destroy(struct wlr_commit *c) {
 | 
					static void commit_destroy(struct wlr_commit *c) {
 | 
				
			||||||
	pixman_region32_fini(&c->surface_damage);
 | 
					 | 
				
			||||||
	pixman_region32_fini(&c->opaque_region);
 | 
						pixman_region32_fini(&c->opaque_region);
 | 
				
			||||||
	pixman_region32_fini(&c->input_region);
 | 
						pixman_region32_fini(&c->input_region);
 | 
				
			||||||
	pixman_region32_fini(&c->buffer_damage);
 | 
						pixman_region32_fini(&c->damage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (c->buffer) {
 | 
				
			||||||
 | 
							compositor_buffer_unref(c->compositor, c->buffer);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_signal_emit_safe(&c->events.destroy, c);
 | 
						wlr_signal_emit_safe(&c->events.destroy, c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -206,8 +225,17 @@ static void surface_damage(struct wl_client *client, struct wl_resource *res,
 | 
				
			||||||
	struct wlr_surface_2 *surf = wlr_surface_from_resource_2(res);
 | 
						struct wlr_surface_2 *surf = wlr_surface_from_resource_2(res);
 | 
				
			||||||
	struct wlr_commit *commit = wlr_surface_get_pending(surf);
 | 
						struct wlr_commit *commit = wlr_surface_get_pending(surf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pixman_region32_union_rect(&commit->surface_damage,
 | 
						/*
 | 
				
			||||||
		&commit->surface_damage, x, y, width, height);
 | 
						 * We choose to not track surface-coordinate damage; it's not worth the
 | 
				
			||||||
 | 
						 * effort. Clients are recommended by the wayland protocol to use
 | 
				
			||||||
 | 
						 * buffer-coordinate damage instead.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * We still need to acknowledge that damage happened, so we damage the
 | 
				
			||||||
 | 
						 * entire buffer instead.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pixman_region32_union_rect(&commit->damage,
 | 
				
			||||||
 | 
							&commit->damage, 0, 0, UINT_MAX, UINT_MAX);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void callback_resource_destroy(struct wl_resource *resource) {
 | 
					static void callback_resource_destroy(struct wl_resource *resource) {
 | 
				
			||||||
| 
						 | 
					@ -305,28 +333,43 @@ static void surface_damage_buffer(struct wl_client *client, struct wl_resource *
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pixman_region32_union_rect(&commit->buffer_damage,
 | 
						pixman_region32_union_rect(&commit->damage,
 | 
				
			||||||
		&commit->buffer_damage, x, y, width, height);
 | 
							&commit->damage, x, y, width, height);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void surface_commit(struct wl_client *client, struct wl_resource *res) {
 | 
					static void surface_commit(struct wl_client *client, struct wl_resource *res) {
 | 
				
			||||||
	struct wlr_surface_2 *surf = wlr_surface_from_resource_2(res);
 | 
						struct wlr_surface_2 *surf = wlr_surface_from_resource_2(res);
 | 
				
			||||||
 | 
						struct wlr_compositor *comp = surf->compositor;
 | 
				
			||||||
	struct wlr_commit *commit = wlr_surface_get_pending(surf);
 | 
						struct wlr_commit *commit = wlr_surface_get_pending(surf);
 | 
				
			||||||
 | 
						struct wlr_commit *previous = wlr_surface_get_latest(surf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	commit->committed = true;
 | 
						commit->committed = true;
 | 
				
			||||||
	wl_list_insert(&surf->committed, &commit->link);
 | 
						wl_list_insert(&surf->committed, &commit->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	surf->pending = commit_create(surf);
 | 
						if (commit->buffer_resource) {
 | 
				
			||||||
	if (!surf->pending) {
 | 
							/*
 | 
				
			||||||
		wl_resource_post_no_memory(surf->resource);
 | 
							 * If we're complete, that means that we can safely "steal" the
 | 
				
			||||||
		return;
 | 
							 * buffer from the previous commit, as we're going to prune it
 | 
				
			||||||
 | 
							 * right after this block.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * This is an optimisation for wl_shm buffers specifically,
 | 
				
			||||||
 | 
							 * and allows us to skip some allocations and copies.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							struct wlr_buffer *old = NULL;
 | 
				
			||||||
 | 
							if (previous && previous->ref_cnt == 1 && wlr_commit_is_complete(commit)) {
 | 
				
			||||||
 | 
								old = previous->buffer;
 | 
				
			||||||
 | 
								previous->buffer = NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							commit->buffer = compositor_buffer_create(comp, old, &commit->damage,
 | 
				
			||||||
 | 
								commit->buffer_resource);
 | 
				
			||||||
 | 
						} else if (previous && previous->buffer) {
 | 
				
			||||||
 | 
							commit->buffer = compositor_buffer_ref(comp, previous->buffer);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	surf->pending->buffer_resource = commit->buffer_resource;
 | 
						if (previous) {
 | 
				
			||||||
	pixman_region32_copy(&surf->pending->opaque_region, &commit->opaque_region);
 | 
							wlr_commit_unref(previous);
 | 
				
			||||||
	pixman_region32_copy(&surf->pending->input_region, &commit->input_region);
 | 
						}
 | 
				
			||||||
	surf->pending->transform = commit->transform;
 | 
					 | 
				
			||||||
	surf->pending->scale = commit->scale;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The wayland protocol says we'll signal these in the order they're
 | 
						 * The wayland protocol says we'll signal these in the order they're
 | 
				
			||||||
| 
						 | 
					@ -335,12 +378,28 @@ static void surface_commit(struct wl_client *client, struct wl_resource *res) {
 | 
				
			||||||
	wl_list_insert_list(surf->frame_callbacks.prev, &commit->frame_callbacks);
 | 
						wl_list_insert_list(surf->frame_callbacks.prev, &commit->frame_callbacks);
 | 
				
			||||||
	wl_list_init(&commit->frame_callbacks);
 | 
						wl_list_init(&commit->frame_callbacks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_signal_emit_safe(&commit->events.commit, commit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						surf->pending = commit_create(surf);
 | 
				
			||||||
 | 
						if (!surf->pending) {
 | 
				
			||||||
 | 
							wl_resource_post_no_memory(surf->resource);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Copy old wl_surface state to next pending commit.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						pixman_region32_copy(&surf->pending->opaque_region, &commit->opaque_region);
 | 
				
			||||||
 | 
						pixman_region32_copy(&surf->pending->input_region, &commit->input_region);
 | 
				
			||||||
 | 
						surf->pending->transform = commit->transform;
 | 
				
			||||||
 | 
						surf->pending->scale = commit->scale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_compositor_new_state_args args = {
 | 
						struct wlr_compositor_new_state_args args = {
 | 
				
			||||||
		.old = commit,
 | 
							.old = commit,
 | 
				
			||||||
		.new = surf->pending,
 | 
							.new = surf->pending,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_signal_emit_safe(&commit->events.commit, commit);
 | 
					 | 
				
			||||||
	wlr_signal_emit_safe(&surf->compositor->events.new_state, &args);
 | 
						wlr_signal_emit_safe(&surf->compositor->events.new_state, &args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	surface_prune_commits(surf);
 | 
						surface_prune_commits(surf);
 | 
				
			||||||
| 
						 | 
					@ -492,8 +551,7 @@ static void compositor_display_destroy(struct wl_listener *listener, void *data)
 | 
				
			||||||
	free(comp);
 | 
						free(comp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_compositor *wlr_compositor_create(struct wl_display *display,
 | 
					struct wlr_compositor *wlr_compositor_create(struct wl_display *display) {
 | 
				
			||||||
		struct wlr_renderer *renderer) {
 | 
					 | 
				
			||||||
	struct wlr_compositor *comp = calloc(1, sizeof(*comp));
 | 
						struct wlr_compositor *comp = calloc(1, sizeof(*comp));
 | 
				
			||||||
	if (!comp) {
 | 
						if (!comp) {
 | 
				
			||||||
		wlr_log_errno(WLR_ERROR, "Allocation failed");
 | 
							wlr_log_errno(WLR_ERROR, "Allocation failed");
 | 
				
			||||||
| 
						 | 
					@ -508,7 +566,6 @@ struct wlr_compositor *wlr_compositor_create(struct wl_display *display,
 | 
				
			||||||
		free(comp);
 | 
							free(comp);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	comp->renderer = renderer;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_signal_init(&comp->events.new_surface);
 | 
						wl_signal_init(&comp->events.new_surface);
 | 
				
			||||||
	wl_signal_init(&comp->events.new_surface_2);
 | 
						wl_signal_init(&comp->events.new_surface_2);
 | 
				
			||||||
| 
						 | 
					@ -520,6 +577,16 @@ struct wlr_compositor *wlr_compositor_create(struct wl_display *display,
 | 
				
			||||||
	return comp;
 | 
						return comp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_compositor_set_buffer_impl(struct wlr_compositor *comp,
 | 
				
			||||||
 | 
							void *data, const struct wlr_compositor_buffer_impl *impl) {
 | 
				
			||||||
 | 
						assert(comp);
 | 
				
			||||||
 | 
						assert(impl);
 | 
				
			||||||
 | 
						assert(!comp->buffer_impl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						comp->buffer_data = data;
 | 
				
			||||||
 | 
						comp->buffer_impl = impl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t wlr_compositor_register(struct wlr_compositor *compositor) {
 | 
					uint32_t wlr_compositor_register(struct wlr_compositor *compositor) {
 | 
				
			||||||
	assert(compositor);
 | 
						assert(compositor);
 | 
				
			||||||
	return compositor->ids++;
 | 
						return compositor->ids++;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue