Skip to content
Commits on Source (31)
......@@ -68,8 +68,9 @@ screenshooter_take_shot(struct wl_client *client,
{
struct weston_output *output =
weston_head_from_resource(output_resource)->output;
struct weston_compositor *ec = output->compositor;
struct weston_buffer *buffer =
weston_buffer_from_resource(buffer_resource);
weston_buffer_from_resource(ec, buffer_resource);
if (buffer == NULL) {
wl_resource_post_no_memory(resource);
......
......@@ -926,14 +926,11 @@ struct weston_renderer {
uint32_t width, uint32_t height);
void (*repaint_output)(struct weston_output *output,
pixman_region32_t *output_damage);
void (*flush_damage)(struct weston_surface *surface);
void (*flush_damage)(struct weston_surface *surface,
struct weston_buffer *buffer);
void (*attach)(struct weston_surface *es, struct weston_buffer *buffer);
void (*surface_set_color)(struct weston_surface *surface,
float red, float green,
float blue, float alpha);
void (*destroy)(struct weston_compositor *ec);
/** See weston_surface_get_content_size() */
void (*surface_get_content_size)(struct weston_surface *surface,
int *width, int *height);
......@@ -950,6 +947,9 @@ struct weston_renderer {
const struct weston_drm_format_array *
(*get_supported_formats)(struct weston_compositor *ec);
bool (*fill_buffer_info)(struct weston_compositor *ec,
struct weston_buffer *buffer);
};
enum weston_capability {
......@@ -1174,19 +1174,44 @@ struct weston_buffer {
struct wl_signal destroy_signal;
struct wl_listener destroy_listener;
enum {
WESTON_BUFFER_SHM,
WESTON_BUFFER_DMABUF,
WESTON_BUFFER_RENDERER_OPAQUE,
WESTON_BUFFER_SOLID,
} type;
union {
struct wl_shm_buffer *shm_buffer;
void *dmabuf;
void *legacy_buffer;
struct {
float r, g, b, a;
} solid;
};
int32_t width, height;
uint32_t busy_count;
int y_inverted;
uint32_t passive_count;
enum {
ORIGIN_TOP_LEFT, /* buffer content starts at (0,0) */
ORIGIN_BOTTOM_LEFT, /* buffer content starts at (0, height) */
} buffer_origin;
void *backend_private;
const struct pixel_format_info *pixel_format;
uint64_t format_modifier;
};
enum weston_buffer_reference_type {
BUFFER_REF_NONE,
BUFFER_MAY_BE_ACCESSED,
BUFFER_WILL_NOT_BE_ACCESSED,
};
struct weston_buffer_reference {
struct weston_buffer *buffer;
struct wl_listener destroy_listener;
enum weston_buffer_reference_type type;
};
struct weston_buffer_viewport {
......@@ -1744,6 +1769,18 @@ weston_surface_create(struct weston_compositor *compositor);
struct weston_view *
weston_view_create(struct weston_surface *surface);
struct weston_buffer_reference *
weston_buffer_create_solid_rgba(struct weston_compositor *compositor,
float r, float g, float b, float a);
void
weston_surface_attach_solid(struct weston_surface *surface,
struct weston_buffer_reference *buffer_ref,
int w, int h);
void
weston_buffer_destroy_solid(struct weston_buffer_reference *buffer_ref);
void
weston_view_destroy(struct weston_view *view);
......@@ -1817,7 +1854,8 @@ weston_surface_copy_content(struct weston_surface *surface,
int width, int height);
struct weston_buffer *
weston_buffer_from_resource(struct wl_resource *resource);
weston_buffer_from_resource(struct weston_compositor *ec,
struct wl_resource *resource);
void
weston_compositor_get_time(struct timespec *time);
......@@ -1936,10 +1974,6 @@ struct weston_view_animation *
weston_slide_run(struct weston_view *view, float start, float stop,
weston_view_animation_done_func_t done, void *data);
void
weston_surface_set_color(struct weston_surface *surface,
float red, float green, float blue, float alpha);
void
weston_surface_destroy(struct weston_surface *surface);
......
......@@ -232,12 +232,18 @@ enum wdrm_crtc_property {
*/
enum try_view_on_plane_failure_reasons {
FAILURE_REASONS_NONE = 0,
FAILURE_REASONS_FORCE_RENDERER = (1 << 0),
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE = (1 << 1),
FAILURE_REASONS_DMABUF_MODIFIER_INVALID = (1 << 2),
FAILURE_REASONS_ADD_FB_FAILED = (1 << 3),
FAILURE_REASONS_NO_PLANES_AVAILABLE = (1 << 4),
FAILURE_REASONS_PLANES_REJECTED = (1 << 5),
FAILURE_REASONS_FORCE_RENDERER = 1 << 0,
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE = 1 << 1,
FAILURE_REASONS_DMABUF_MODIFIER_INVALID = 1 << 2,
FAILURE_REASONS_ADD_FB_FAILED = 1 << 3,
FAILURE_REASONS_NO_PLANES_AVAILABLE = 1 << 4,
FAILURE_REASONS_PLANES_REJECTED = 1 << 5,
FAILURE_REASONS_INADEQUATE_CONTENT_PROTECTION = 1 << 6,
FAILURE_REASONS_INCOMPATIBLE_TRANSFORM = 1 << 7,
FAILURE_REASONS_NO_BUFFER = 1 << 8,
FAILURE_REASONS_BUFFER_TYPE = 1 << 9,
FAILURE_REASONS_GLOBAL_ALPHA = 1 << 10,
FAILURE_REASONS_NO_GBM = 1 << 11,
};
/**
......
......@@ -522,22 +522,32 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
struct drm_buffer_fb *buf_fb;
bool is_opaque = weston_view_is_opaque(ev, &ev->transform.boundingbox);
struct linux_dmabuf_buffer *dmabuf;
struct drm_fb *fb;
struct drm_plane *plane;
if (ev->alpha != 1.0f)
if (ev->alpha != 1.0f) {
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_GLOBAL_ALPHA;
return NULL;
}
if (!drm_view_transform_supported(ev, &output->base))
if (!drm_view_transform_supported(ev, &output->base)) {
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_INCOMPATIBLE_TRANSFORM;
return NULL;
}
if (ev->surface->protection_mode == WESTON_SURFACE_PROTECTION_MODE_ENFORCED &&
ev->surface->desired_protection > output->base.current_protection)
ev->surface->desired_protection > output->base.current_protection) {
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_INADEQUATE_CONTENT_PROTECTION;
return NULL;
}
if (!buffer)
if (!buffer) {
*try_view_on_plane_failure_reasons |= FAILURE_REASONS_NO_BUFFER;
return NULL;
}
if (buffer->backend_private) {
buf_fb = buffer->backend_private;
......@@ -550,20 +560,18 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
buf_fb->buffer_destroy_listener.notify = drm_fb_handle_buffer_destroy;
wl_signal_add(&buffer->destroy_signal, &buf_fb->buffer_destroy_listener);
if (wl_shm_buffer_get(buffer->resource))
goto unsuitable;
/* GBM is used for dmabuf import as well as from client wl_buffer. */
if (!b->gbm)
if (!b->gbm) {
*try_view_on_plane_failure_reasons |= FAILURE_REASONS_NO_GBM;
goto unsuitable;
}
dmabuf = linux_dmabuf_buffer_get(buffer->resource);
if (dmabuf) {
fb = drm_fb_get_from_dmabuf(dmabuf, b, is_opaque,
if (buffer->type == WESTON_BUFFER_DMABUF) {
fb = drm_fb_get_from_dmabuf(buffer->dmabuf, b, is_opaque,
&buf_fb->failure_reasons);
if (!fb)
goto unsuitable;
} else {
} else if (buffer->type == WESTON_BUFFER_RENDERER_OPAQUE) {
struct gbm_bo *bo;
bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
......@@ -573,9 +581,14 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
fb = drm_fb_get_from_bo(bo, b, is_opaque, BUFFER_CLIENT);
if (!fb) {
*try_view_on_plane_failure_reasons |=
(1 << FAILURE_REASONS_ADD_FB_FAILED);
gbm_bo_destroy(bo);
goto unsuitable;
}
} else {
*try_view_on_plane_failure_reasons |= FAILURE_REASONS_BUFFER_TYPE;
goto unsuitable;
}
/* Check if this buffer can ever go on any planes. If it can't, we have
......
......@@ -93,7 +93,8 @@ drm_plane_state_free(struct drm_plane_state *state, bool force)
if (force || state != state->plane->state_cur) {
drm_fb_unref(state->fb);
weston_buffer_reference(&state->fb_ref.buffer, NULL);
weston_buffer_reference(&state->fb_ref.buffer, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&state->fb_ref.release, NULL);
free(state);
}
......@@ -135,10 +136,20 @@ drm_plane_state_duplicate(struct drm_output_state *state_output,
* buffer, then we must also transfer the reference on the client
* buffer. */
if (src->fb) {
struct weston_buffer *buffer;
dst->fb = drm_fb_ref(src->fb);
memset(&dst->fb_ref, 0, sizeof(dst->fb_ref));
weston_buffer_reference(&dst->fb_ref.buffer,
src->fb_ref.buffer.buffer);
if (src->fb->type == BUFFER_CLIENT ||
src->fb->type == BUFFER_DMABUF) {
buffer = src->fb_ref.buffer.buffer;
} else {
buffer = NULL;
}
weston_buffer_reference(&dst->fb_ref.buffer, buffer,
buffer ? BUFFER_MAY_BE_ACCESSED :
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&dst->fb_ref.release,
src->fb_ref.release.buffer_release);
} else {
......
......@@ -139,7 +139,8 @@ drm_output_try_view_on_plane(struct drm_plane *plane,
assert(state->fb_ref.buffer.buffer == NULL);
assert(state->fb_ref.release.buffer_release == NULL);
weston_buffer_reference(&state->fb_ref.buffer,
surface->buffer_ref.buffer);
surface->buffer_ref.buffer,
BUFFER_MAY_BE_ACCESSED);
weston_buffer_release_reference(&state->fb_ref.release,
surface->buffer_release_ref.buffer_release);
......@@ -169,7 +170,6 @@ cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev)
int i;
assert(buffer && buffer->shm_buffer);
assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
assert(buffer->width <= b->cursor_width);
assert(buffer->height <= b->cursor_height);
......@@ -432,7 +432,6 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
struct weston_view *ev = pnode->view;
struct weston_buffer *buffer;
struct wl_shm_buffer *shmbuf;
struct drm_fb *fb = NULL;
bool view_matches_entire_output, scanout_has_view_assigned;
......@@ -448,15 +447,20 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
}
buffer = ev->surface->buffer_ref.buffer;
shmbuf = wl_shm_buffer_get(buffer->resource);
if (shmbuf) {
if (buffer->type == WESTON_BUFFER_SOLID) {
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
return NULL;
} else if (buffer->type == WESTON_BUFFER_SHM) {
if (!output->cursor_plane || b->cursors_are_broken) {
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
return NULL;
}
if (wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888) {
/* Even though this is a SHM buffer, pixel_format stores the
* format code as DRM FourCC */
if (buffer->pixel_format->format != DRM_FORMAT_ARGB8888) {
drm_debug(b, "\t\t\t\t[view] not placing view %p on "
"plane; SHM buffers must be ARGB8888 for "
"cursor view\n", ev);
......@@ -485,8 +489,11 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
fb = drm_fb_get_from_view(state, ev,
&pnode->try_view_on_plane_failure_reasons);
if (!fb)
if (!fb) {
drm_debug(b, "\t\t\t[view] couldn't get FB for view: 0x%lx\n",
(unsigned long) pnode->try_view_on_plane_failure_reasons);
return NULL;
}
possible_plane_mask = fb->plane_mask;
}
......@@ -512,7 +519,7 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
switch (plane->type) {
case WDRM_PLANE_TYPE_CURSOR:
assert(shmbuf);
assert(buffer->shm_buffer);
assert(plane == output->cursor_plane);
break;
case WDRM_PLANE_TYPE_PRIMARY:
......@@ -770,6 +777,17 @@ drm_output_propose_state(struct weston_output *output_base,
force_renderer = true;
}
/* We can support this with the 'CRTC background colour' property,
* if it is fullscreen (i.e. we disable the primary plane), and
* opaque (as it is only shown in the absence of any covering
* plane, not as a replacement for the primary plane per se). */
if (ev->surface->buffer_ref.buffer &&
ev->surface->buffer_ref.buffer->type == WESTON_BUFFER_SOLID) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
"(solid-colour surface)\n", ev);
force_renderer = true;
}
if (pnode->surf_xform.transform != NULL ||
!pnode->surf_xform.identity_pipeline) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
......@@ -957,14 +975,18 @@ drm_assign_planes(struct weston_output *output_base)
* renderer and since the pixman renderer keeps a reference
* to the buffer anyway, there is no side effects.
*/
if (b->use_pixman ||
(weston_view_has_valid_buffer(ev) &&
(!wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
(ev->surface->width <= b->cursor_width &&
ev->surface->height <= b->cursor_height))))
ev->surface->keep_buffer = true;
else
ev->surface->keep_buffer = false;
ev->surface->keep_buffer = false;
if (weston_view_has_valid_buffer(ev)) {
struct weston_buffer *buffer =
ev->surface->buffer_ref.buffer;
if (buffer->type == WESTON_BUFFER_DMABUF ||
buffer->type == WESTON_BUFFER_RENDERER_OPAQUE)
ev->surface->keep_buffer = true;
else if (buffer->type == WESTON_BUFFER_SHM &&
(ev->surface->width <= b->cursor_width &&
ev->surface->height <= b->cursor_height))
ev->surface->keep_buffer = true;
}
/* This is a bit unpleasant, but lacking a temporary place to
* hang a plane off the view, we have to do a nested walk.
......
......@@ -52,6 +52,7 @@
#include <time.h>
#include <errno.h>
#include <inttypes.h>
#include <drm_fourcc.h>
#include "timeline.h"
......@@ -629,14 +630,6 @@ weston_surface_create(struct weston_compositor *compositor)
return surface;
}
WL_EXPORT void
weston_surface_set_color(struct weston_surface *surface,
float red, float green, float blue, float alpha)
{
surface->compositor->renderer->surface_set_color(surface, red, green, blue, alpha);
surface->is_opaque = !(alpha < 1.0);
}
WL_EXPORT void
weston_view_to_global_float(struct weston_view *view,
float sx, float sy, float *x, float *y)
......@@ -1982,7 +1975,11 @@ weston_view_is_opaque(struct weston_view *ev, pixman_region32_t *region)
WL_EXPORT bool
weston_view_has_valid_buffer(struct weston_view *ev)
{
return ev->surface->buffer_ref.buffer != NULL;
if (!ev->surface->buffer_ref.buffer)
return false;
if (!ev->surface->buffer_ref.buffer->resource)
return false;
return true;
}
/** Check if the view matches the entire output
......@@ -2329,7 +2326,8 @@ weston_surface_destroy(struct weston_surface *surface)
weston_surface_state_fini(&surface->pending);
weston_buffer_reference(&surface->buffer_ref, NULL);
weston_buffer_reference(&surface->buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&surface->buffer_release_ref, NULL);
pixman_region32_fini(&surface->damage);
......@@ -2380,14 +2378,23 @@ weston_buffer_destroy_handler(struct wl_listener *listener, void *data)
struct weston_buffer *buffer =
container_of(listener, struct weston_buffer, destroy_listener);
buffer->resource = NULL;
buffer->shm_buffer = NULL;
if (buffer->busy_count + buffer->passive_count > 0)
return;
weston_signal_emit_mutable(&buffer->destroy_signal, buffer);
free(buffer);
}
WL_EXPORT struct weston_buffer *
weston_buffer_from_resource(struct wl_resource *resource)
weston_buffer_from_resource(struct weston_compositor *ec,
struct wl_resource *resource)
{
struct weston_buffer *buffer;
struct wl_shm_buffer *shm;
struct linux_dmabuf_buffer *dmabuf;
struct wl_listener *listener;
listener = wl_resource_get_destroy_listener(resource,
......@@ -2404,45 +2411,113 @@ weston_buffer_from_resource(struct wl_resource *resource)
buffer->resource = resource;
wl_signal_init(&buffer->destroy_signal);
buffer->destroy_listener.notify = weston_buffer_destroy_handler;
buffer->y_inverted = 1;
wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
return buffer;
}
if ((shm = wl_shm_buffer_get(buffer->resource))) {
buffer->type = WESTON_BUFFER_SHM;
buffer->shm_buffer = shm;
buffer->width = wl_shm_buffer_get_width(shm);
buffer->height = wl_shm_buffer_get_height(shm);
buffer->buffer_origin = ORIGIN_TOP_LEFT;
/* wl_shm might create a buffer with an unknown format, so check
* and reject */
buffer->pixel_format =
pixel_format_get_info_shm(wl_shm_buffer_get_format(shm));
buffer->format_modifier = DRM_FORMAT_MOD_LINEAR;
if (!buffer->pixel_format)
goto fail;
} else if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource))) {
buffer->type = WESTON_BUFFER_DMABUF;
buffer->dmabuf = dmabuf;
buffer->width = dmabuf->attributes.width;
buffer->height = dmabuf->attributes.height;
buffer->pixel_format =
pixel_format_get_info(dmabuf->attributes.format);
/* dmabuf import should assure we don't create a buffer with an
* unknown format */
assert(buffer->pixel_format);
buffer->format_modifier = dmabuf->attributes.modifier[0];
if (dmabuf->attributes.flags & ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT)
buffer->buffer_origin = ORIGIN_BOTTOM_LEFT;
else
buffer->buffer_origin = ORIGIN_TOP_LEFT;
} else {
/* Only taken for legacy EGL buffers */
if (!ec->renderer->fill_buffer_info ||
!ec->renderer->fill_buffer_info(ec, buffer)) {
goto fail;
}
buffer->type = WESTON_BUFFER_RENDERER_OPAQUE;
}
static void
weston_buffer_reference_handle_destroy(struct wl_listener *listener,
void *data)
{
struct weston_buffer_reference *ref =
container_of(listener, struct weston_buffer_reference,
destroy_listener);
/* Don't accept any formats we can't reason about: the importer should
* make sure this never happens */
assert(buffer->pixel_format);
assert((struct weston_buffer *)data == ref->buffer);
ref->buffer = NULL;
return buffer;
fail:
wl_list_remove(&buffer->destroy_listener.link);
free(buffer);
return NULL;
}
WL_EXPORT void
weston_buffer_reference(struct weston_buffer_reference *ref,
struct weston_buffer *buffer)
struct weston_buffer *buffer,
enum weston_buffer_reference_type type)
{
if (ref->buffer && buffer != ref->buffer) {
ref->buffer->busy_count--;
if (ref->buffer->busy_count == 0) {
assert(wl_resource_get_client(ref->buffer->resource));
wl_buffer_send_release(ref->buffer->resource);
}
wl_list_remove(&ref->destroy_listener.link);
}
struct weston_buffer_reference old_ref = *ref;
assert(buffer != NULL || type == BUFFER_WILL_NOT_BE_ACCESSED);
if (buffer && buffer != ref->buffer) {
buffer->busy_count++;
wl_signal_add(&buffer->destroy_signal,
&ref->destroy_listener);
if (buffer == ref->buffer && type == ref->type)
return;
/* First ref the incoming buffer, so we keep positive refcount */
if (buffer) {
if (type == BUFFER_MAY_BE_ACCESSED)
buffer->busy_count++;
else
buffer->passive_count++;
}
ref->buffer = buffer;
ref->destroy_listener.notify = weston_buffer_reference_handle_destroy;
ref->type = type;
/* Now drop refs to the old buffer, if any */
if (!old_ref.buffer)
return;
ref = NULL; /* will no longer be accessed */
if (old_ref.type == BUFFER_MAY_BE_ACCESSED) {
assert(old_ref.buffer->busy_count > 0);
old_ref.buffer->busy_count--;
/* If the wl_buffer lives, then hold on to the weston_buffer,
* but send a release event to the client */
if (old_ref.buffer->busy_count == 0 &&
old_ref.buffer->resource) {
assert(wl_resource_get_client(old_ref.buffer->resource));
wl_buffer_send_release(old_ref.buffer->resource);
}
} else if (old_ref.type == BUFFER_WILL_NOT_BE_ACCESSED) {
assert(old_ref.buffer->passive_count > 0);
old_ref.buffer->passive_count--;
} else {
assert(!"unknown buffer ref type");
}
/* If the wl_buffer has gone and this was the last ref, destroy the
* weston_buffer, since we'll never need it again */
if (old_ref.buffer->busy_count + old_ref.buffer->passive_count == 0 &&
!old_ref.buffer->resource) {
weston_signal_emit_mutable(&old_ref.buffer->destroy_signal,
old_ref.buffer);
free(old_ref.buffer);
}
}
static void
......@@ -2507,11 +2582,88 @@ weston_buffer_release_move(struct weston_buffer_release_reference *dest,
weston_buffer_release_reference(src, NULL);
}
WL_EXPORT struct weston_buffer_reference *
weston_buffer_create_solid_rgba(struct weston_compositor *compositor,
float r, float g, float b, float a)
{
struct weston_buffer_reference *ret = zalloc(sizeof(*ret));
struct weston_buffer *buffer;
if (!ret)
return NULL;
buffer = zalloc(sizeof(*buffer));
if (!buffer) {
free(ret);
return NULL;
}
wl_signal_init(&buffer->destroy_signal);
buffer->type = WESTON_BUFFER_SOLID;
buffer->width = 1;
buffer->height = 1;
buffer->buffer_origin = ORIGIN_TOP_LEFT;
buffer->solid.r = r;
buffer->solid.g = g;
buffer->solid.b = b;
buffer->solid.a = a;
if (a == 1.0) {
buffer->pixel_format =
pixel_format_get_info_shm(WL_SHM_FORMAT_XRGB8888);
} else {
buffer->pixel_format =
pixel_format_get_info_shm(WL_SHM_FORMAT_ARGB8888);
}
buffer->format_modifier = DRM_FORMAT_MOD_LINEAR;
weston_buffer_reference(ret, buffer, BUFFER_MAY_BE_ACCESSED);
return ret;
}
WL_EXPORT void
weston_surface_attach_solid(struct weston_surface *surface,
struct weston_buffer_reference *buffer_ref,
int w, int h)
{
struct weston_buffer *buffer = buffer_ref->buffer;
assert(buffer);
assert(buffer->type == WESTON_BUFFER_SOLID);
weston_buffer_reference(&surface->buffer_ref, buffer,
BUFFER_MAY_BE_ACCESSED);
surface->compositor->renderer->attach(surface, buffer);
weston_surface_set_size(surface, w, h);
pixman_region32_fini(&surface->opaque);
if (buffer->solid.a == 1.0) {
surface->is_opaque = true;
pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
} else {
pixman_region32_init(&surface->opaque);
}
}
WL_EXPORT void
weston_buffer_destroy_solid(struct weston_buffer_reference *buffer_ref)
{
assert(buffer_ref);
assert(buffer_ref->buffer);
assert(buffer_ref->type == BUFFER_MAY_BE_ACCESSED);
assert(buffer_ref->buffer->type == WESTON_BUFFER_SOLID);
weston_buffer_reference(buffer_ref, NULL, BUFFER_WILL_NOT_BE_ACCESSED);
free(buffer_ref);
}
static void
weston_surface_attach(struct weston_surface *surface,
struct weston_buffer *buffer)
{
weston_buffer_reference(&surface->buffer_ref, buffer);
weston_buffer_reference(&surface->buffer_ref, buffer,
buffer ? BUFFER_MAY_BE_ACCESSED :
BUFFER_WILL_NOT_BE_ACCESSED);
if (!buffer) {
if (weston_surface_is_mapped(surface))
......@@ -2553,9 +2705,10 @@ weston_output_damage(struct weston_output *output)
static void
surface_flush_damage(struct weston_surface *surface)
{
if (surface->buffer_ref.buffer &&
wl_shm_buffer_get(surface->buffer_ref.buffer->resource))
surface->compositor->renderer->flush_damage(surface);
struct weston_buffer *buffer = surface->buffer_ref.buffer;
if (buffer && buffer->type == WESTON_BUFFER_SHM)
surface->compositor->renderer->flush_damage(surface, buffer);
if (pixman_region32_not_empty(&surface->damage))
TL_POINT(surface->compositor, "core_flush_damage", TLP_SURFACE(surface),
......@@ -2647,7 +2800,9 @@ output_accumulate_damage(struct weston_output *output)
* clients to use single-buffering.
*/
if (!pnode->surface->keep_buffer) {
weston_buffer_reference(&pnode->surface->buffer_ref, NULL);
weston_buffer_reference(&pnode->surface->buffer_ref,
pnode->surface->buffer_ref.buffer,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(
&pnode->surface->buffer_release_ref, NULL);
}
......@@ -3426,10 +3581,11 @@ surface_attach(struct wl_client *client,
struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
{
struct weston_surface *surface = wl_resource_get_user_data(resource);
struct weston_compositor *ec = surface->compositor;
struct weston_buffer *buffer = NULL;
if (buffer_resource) {
buffer = weston_buffer_from_resource(buffer_resource);
buffer = weston_buffer_from_resource(ec, buffer_resource);
if (buffer == NULL) {
wl_client_post_no_memory(client);
return;
......@@ -3947,14 +4103,7 @@ surface_commit(struct wl_client *client, struct wl_resource *resource)
return;
}
/* We support fences for both wp_linux_dmabuf and opaque EGL
* buffers, as mandated by minor version 2 of the
* zwp_linux_explicit_synchronization_v1 protocol. Since
* renderers that support fences currently only support these
* two buffer types plus SHM buffers, we can just check for the
* SHM buffer case here.
*/
if (wl_shm_buffer_get(surface->pending.buffer->resource)) {
if (surface->pending.buffer->type == WESTON_BUFFER_SHM) {
fd_clear(&surface->pending.acquire_fence_fd);
wl_resource_post_error(surface->synchronization_resource,
ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_UNSUPPORTED_BUFFER,
......@@ -4180,7 +4329,8 @@ weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
struct weston_surface *surface = sub->surface;
weston_surface_commit_state(surface, &sub->cached);
weston_buffer_reference(&sub->cached_buffer_ref, NULL);
weston_buffer_reference(&sub->cached_buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_surface_commit_subsurface_order(surface);
......@@ -4217,7 +4367,10 @@ weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
weston_surface_state_set_buffer(&sub->cached,
surface->pending.buffer);
weston_buffer_reference(&sub->cached_buffer_ref,
surface->pending.buffer);
surface->pending.buffer,
surface->pending.buffer ?
BUFFER_MAY_BE_ACCESSED :
BUFFER_WILL_NOT_BE_ACCESSED);
weston_presentation_feedback_discard_list(
&sub->cached.feedback_list);
/* zwp_surface_synchronization_v1.set_acquire_fence */
......@@ -4799,7 +4952,8 @@ weston_subsurface_destroy(struct weston_subsurface *sub)
weston_subsurface_unlink_parent(sub);
weston_surface_state_fini(&sub->cached);
weston_buffer_reference(&sub->cached_buffer_ref, NULL);
weston_buffer_reference(&sub->cached_buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
sub->surface->committed = NULL;
sub->surface->committed_private = NULL;
......@@ -7442,43 +7596,57 @@ static void
debug_scene_view_print_buffer(FILE *fp, struct weston_view *view)
{
struct weston_buffer *buffer = view->surface->buffer_ref.buffer;
struct wl_shm_buffer *shm;
struct linux_dmabuf_buffer *dmabuf;
const struct pixel_format_info *pixel_info = NULL;
char *modifier_name;
if (!buffer) {
fprintf(fp, "\t\t[buffer not available]\n");
return;
}
shm = wl_shm_buffer_get(buffer->resource);
if (shm) {
uint32_t _format = wl_shm_buffer_get_format(shm);
pixel_info = pixel_format_get_info_shm(_format);
switch (buffer->type) {
case WESTON_BUFFER_SHM:
fprintf(fp, "\t\tSHM buffer\n");
fprintf(fp, "\t\t\tformat: 0x%lx %s\n",
(unsigned long) _format,
pixel_info ? pixel_info->drm_format_name : "UNKNOWN");
return;
break;
case WESTON_BUFFER_DMABUF:
fprintf(fp, "\t\tdmabuf buffer\n");
break;
case WESTON_BUFFER_SOLID:
fprintf(fp, "\t\tsolid-colour buffer\n");
fprintf(fp, "\t\t\t[R %f, G %f, B %f, A %f]\n",
buffer->solid.r, buffer->solid.g, buffer->solid.b,
buffer->solid.a);
break;
case WESTON_BUFFER_RENDERER_OPAQUE:
fprintf(fp, "\t\tEGL buffer:\n");
fprintf(fp, "\t\t\t[format may be inaccurate]\n");
break;
}
dmabuf = linux_dmabuf_buffer_get(buffer->resource);
if (dmabuf) {
uint64_t modifier = dmabuf->attributes.modifier[0];
char *modifier_name = pixel_format_get_modifier(modifier);
pixel_info = pixel_format_get_info(dmabuf->attributes.format);
fprintf(fp, "\t\tdmabuf buffer\n");
fprintf(fp, "\t\t\tformat: 0x%lx %s\n",
(unsigned long) dmabuf->attributes.format,
pixel_info ? pixel_info->drm_format_name : "UNKNOWN");
if (buffer->busy_count > 0) {
fprintf(fp, "\t\t\t[%d references may use buffer content]\n",
buffer->busy_count);
} else {
fprintf(fp, "\t\t\t[buffer has been released to client]\n");
}
fprintf(fp, "\t\t\tmodifier: %s\n", modifier_name ? modifier_name :
"Failed to convert to a modifier name");
free(modifier_name);
return;
if (buffer->pixel_format) {
fprintf(fp, "\t\t\tformat: 0x%lx %s\n",
(unsigned long) buffer->pixel_format->format,
buffer->pixel_format->drm_format_name);
} else {
fprintf(fp, "\t\t\t[unknown format]\n");
}
fprintf(fp, "\t\tEGL buffer\n");
modifier_name = pixel_format_get_modifier(buffer->format_modifier);
fprintf(fp, "\t\t\tmodifier: %s\n",
modifier_name ?
modifier_name : "Failed to convert to a modifier name");
free(modifier_name);
fprintf(fp, "\t\t\twidth: %d, height: %d\n",
buffer->width, buffer->height);
if (buffer->buffer_origin == ORIGIN_BOTTOM_LEFT)
fprintf(fp, "\t\t\tbottom-left origin\n");
}
static void
......
......@@ -420,6 +420,7 @@ drag_surface_configure(struct weston_drag *drag,
assert((pointer != NULL && touch == NULL) ||
(pointer == NULL && touch != NULL));
/* XXX: Why are we checking for a valid buffer here too ... ? */
if (!weston_surface_is_mapped(es) && es->buffer_ref.buffer) {
if (pointer && pointer->sprite &&
weston_view_is_mapped(pointer->sprite))
......
......@@ -50,7 +50,8 @@ weston_buffer_send_server_error(struct weston_buffer *buffer,
const char *msg);
void
weston_buffer_reference(struct weston_buffer_reference *ref,
struct weston_buffer *buffer);
struct weston_buffer *buffer,
enum weston_buffer_reference_type type);
void
weston_buffer_release_move(struct weston_buffer_release_reference *dest,
......
......@@ -47,7 +47,8 @@ noop_renderer_repaint_output(struct weston_output *output,
}
static void
noop_renderer_flush_damage(struct weston_surface *surface)
noop_renderer_flush_damage(struct weston_surface *surface,
struct weston_buffer *buffer)
{
}
......@@ -62,13 +63,19 @@ noop_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
if (!buffer)
return;
shm_buffer = wl_shm_buffer_get(buffer->resource);
if (!shm_buffer) {
switch (buffer->type) {
case WESTON_BUFFER_SOLID:
/* no-op, early exit */
return;
case WESTON_BUFFER_SHM:
/* fine */
break;
default:
weston_log("No-op renderer supports only SHM buffers\n");
return;
}
shm_buffer = buffer->shm_buffer;
data = wl_shm_buffer_get_data(shm_buffer);
stride = wl_shm_buffer_get_stride(shm_buffer);
width = wl_shm_buffer_get_width(shm_buffer);
......@@ -89,12 +96,6 @@ noop_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
buffer->height = height;
}
static void
noop_renderer_surface_set_color(struct weston_surface *surface,
float red, float green, float blue, float alpha)
{
}
static void
noop_renderer_destroy(struct weston_compositor *ec)
{
......@@ -115,7 +116,6 @@ noop_renderer_init(struct weston_compositor *ec)
renderer->repaint_output = noop_renderer_repaint_output;
renderer->flush_damage = noop_renderer_flush_damage;
renderer->attach = noop_renderer_attach;
renderer->surface_set_color = noop_renderer_surface_set_color;
renderer->destroy = noop_renderer_destroy;
ec->renderer = renderer;
......
......@@ -598,7 +598,8 @@ pixman_renderer_repaint_output(struct weston_output *output,
}
static void
pixman_renderer_flush_damage(struct weston_surface *surface)
pixman_renderer_flush_damage(struct weston_surface *surface,
struct weston_buffer *buffer)
{
/* No-op for pixman renderer */
}
......@@ -619,6 +620,26 @@ buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
ps->buffer_destroy_listener.notify = NULL;
}
static void
pixman_renderer_surface_set_color(struct weston_surface *es,
float red, float green, float blue, float alpha)
{
struct pixman_surface_state *ps = get_surface_state(es);
pixman_color_t color;
color.red = red * 0xffff;
color.green = green * 0xffff;
color.blue = blue * 0xffff;
color.alpha = alpha * 0xffff;
if (ps->image) {
pixman_image_unref(ps->image);
ps->image = NULL;
}
ps->image = pixman_image_create_solid_fill(&color);
}
static void
pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
{
......@@ -626,7 +647,9 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
struct wl_shm_buffer *shm_buffer;
const struct pixel_format_info *pixel_info;
weston_buffer_reference(&ps->buffer_ref, buffer);
weston_buffer_reference(&ps->buffer_ref, buffer,
buffer ? BUFFER_MAY_BE_ACCESSED :
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&ps->buffer_release_ref,
es->buffer_release_ref.buffer_release);
......@@ -643,20 +666,34 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
if (!buffer)
return;
shm_buffer = wl_shm_buffer_get(buffer->resource);
if (buffer->type == WESTON_BUFFER_SOLID) {
pixman_renderer_surface_set_color(es,
buffer->solid.r,
buffer->solid.g,
buffer->solid.b,
buffer->solid.a);
weston_buffer_reference(&ps->buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
return;
}
if (! shm_buffer) {
if (buffer->type != WESTON_BUFFER_SHM) {
weston_log("Pixman renderer supports only SHM buffers\n");
weston_buffer_reference(&ps->buffer_ref, NULL);
weston_buffer_reference(&ps->buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
return;
}
shm_buffer = buffer->shm_buffer;
pixel_info = pixel_format_get_info_shm(wl_shm_buffer_get_format(shm_buffer));
if (!pixel_info || !pixman_format_supported_source(pixel_info->pixman_format)) {
weston_log("Unsupported SHM buffer format 0x%x\n",
wl_shm_buffer_get_format(shm_buffer));
weston_buffer_reference(&ps->buffer_ref, NULL);
weston_buffer_reference(&ps->buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
weston_buffer_send_server_error(buffer,
"disconnecting due to unhandled buffer type");
......@@ -665,10 +702,6 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
es->is_opaque = pixel_format_is_opaque(pixel_info);
buffer->shm_buffer = shm_buffer;
buffer->width = wl_shm_buffer_get_width(shm_buffer);
buffer->height = wl_shm_buffer_get_height(shm_buffer);
ps->image = pixman_image_create_bits(pixel_info->pixman_format,
buffer->width, buffer->height,
wl_shm_buffer_get_data(shm_buffer),
......@@ -696,7 +729,8 @@ pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
pixman_image_unref(ps->image);
ps->image = NULL;
}
weston_buffer_reference(&ps->buffer_ref, NULL);
weston_buffer_reference(&ps->buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
free(ps);
}
......@@ -750,26 +784,6 @@ pixman_renderer_create_surface(struct weston_surface *surface)
return 0;
}
static void
pixman_renderer_surface_set_color(struct weston_surface *es,
float red, float green, float blue, float alpha)
{
struct pixman_surface_state *ps = get_surface_state(es);
pixman_color_t color;
color.red = red * 0xffff;
color.green = green * 0xffff;
color.blue = blue * 0xffff;
color.alpha = alpha * 0xffff;
if (ps->image) {
pixman_image_unref(ps->image);
ps->image = NULL;
}
ps->image = pixman_image_create_solid_fill(&color);
}
static void
pixman_renderer_destroy(struct weston_compositor *ec)
{
......@@ -867,7 +881,6 @@ pixman_renderer_init(struct weston_compositor *ec)
renderer->base.repaint_output = pixman_renderer_repaint_output;
renderer->base.flush_damage = pixman_renderer_flush_damage;
renderer->base.attach = pixman_renderer_attach;
renderer->base.surface_set_color = pixman_renderer_surface_set_color;
renderer->base.destroy = pixman_renderer_destroy;
renderer->base.surface_get_content_size =
pixman_renderer_surface_get_content_size;
......
......@@ -888,7 +888,7 @@ ensure_surface_buffer_is_ready(struct gl_renderer *gr,
assert(gr->has_native_fence_sync);
/* We should only get a fence for non-SHM buffers, since surface
* commit would have failed otherwise. */
assert(wl_shm_buffer_get(buffer->resource) == NULL);
assert(buffer->type != WESTON_BUFFER_SHM);
attribs[1] = dup(surface->acquire_fence_fd);
if (attribs[1] == -1) {
......@@ -1832,22 +1832,27 @@ gl_format_from_internal(GLenum internal_format)
}
static void
gl_renderer_flush_damage(struct weston_surface *surface)
gl_renderer_flush_damage(struct weston_surface *surface,
struct weston_buffer *buffer)
{
const struct weston_testsuite_quirks *quirks =
&surface->compositor->test_data.test_quirks;
struct gl_surface_state *gs = get_surface_state(surface);
struct weston_buffer *buffer = gs->buffer_ref.buffer;
struct weston_view *view;
bool texture_used;
pixman_box32_t *rectangles;
uint8_t *data;
int i, j, n;
assert(buffer);
pixman_region32_union(&gs->texture_damage,
&gs->texture_damage, &surface->damage);
if (!buffer)
/* This can happen if a SHM wl_buffer gets destroyed before we flush
* damage, because wayland-server just nukes the wl_shm_buffer from
* underneath us */
if (!buffer->shm_buffer)
return;
/* Avoid upload, if the texture won't be used this time.
......@@ -1926,7 +1931,8 @@ done:
pixman_region32_init(&gs->texture_damage);
gs->needs_full_upload = false;
weston_buffer_reference(&gs->buffer_ref, NULL);
weston_buffer_reference(&gs->buffer_ref, buffer,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
}
......@@ -1966,10 +1972,6 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
int num_planes;
bool using_glesv2 = gr->gl_version < gr_gl_version(3, 0);
buffer->shm_buffer = shm_buffer;
buffer->width = wl_shm_buffer_get_width(shm_buffer);
buffer->height = wl_shm_buffer_get_height(shm_buffer);
num_planes = 1;
gs->offset[0] = 0;
gs->hsub[0] = 1;
......@@ -2158,6 +2160,65 @@ unsupported:
}
}
static bool
gl_renderer_fill_buffer_info(struct weston_compositor *ec,
struct weston_buffer *buffer)
{
struct gl_renderer *gr = get_renderer(ec);
EGLint format;
uint32_t fourcc;
EGLint y_inverted;
bool ret = true;
buffer->legacy_buffer = (struct wl_buffer *)buffer->resource;
ret &= gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
EGL_WIDTH, &buffer->width);
ret &= gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
EGL_HEIGHT, &buffer->height);
ret &= gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
EGL_TEXTURE_FORMAT, &format);
if (!ret)
return false;
/* The legacy EGL buffer interface only describes the channels we can
* sample from; not their depths or order. Take a stab at something
* which might be representative. Pessimise extremely hard for
* TEXTURE_EXTERNAL_OES. */
switch (format) {
case EGL_TEXTURE_RGB:
fourcc = DRM_FORMAT_XRGB8888;
break;
case EGL_TEXTURE_EXTERNAL_WL:
case EGL_TEXTURE_RGBA:
fourcc = DRM_FORMAT_ARGB8888;
break;
case EGL_TEXTURE_Y_XUXV_WL:
fourcc = DRM_FORMAT_YUYV;
break;
case EGL_TEXTURE_Y_UV_WL:
fourcc = DRM_FORMAT_NV12;
break;
case EGL_TEXTURE_Y_U_V_WL:
fourcc = DRM_FORMAT_YUV420;
break;
}
buffer->pixel_format = pixel_format_get_info(fourcc);
assert(buffer->pixel_format);
buffer->format_modifier = DRM_FORMAT_MOD_INVALID;
/* Assume scanout co-ordinate space i.e. (0,0) is top-left
* if the query fails */
ret = gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
EGL_WAYLAND_Y_INVERTED_WL, &y_inverted);
if (!ret || y_inverted)
buffer->buffer_origin = ORIGIN_TOP_LEFT;
else
buffer->buffer_origin = ORIGIN_BOTTOM_LEFT;
return true;
}
static void
gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer,
uint32_t format)
......@@ -2169,14 +2230,6 @@ gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer,
GLenum target;
int i, num_planes;
buffer->legacy_buffer = (struct wl_buffer *)buffer->resource;
gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
EGL_WIDTH, &buffer->width);
gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
EGL_HEIGHT, &buffer->height);
gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
EGL_WAYLAND_Y_INVERTED_WL, &buffer->y_inverted);
for (i = 0; i < gs->num_images; i++) {
egl_image_unref(gs->images[i]);
gs->images[i] = NULL;
......@@ -2239,7 +2292,7 @@ gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer,
gs->pitch = buffer->width;
gs->height = buffer->height;
gs->buffer_type = BUFFER_TYPE_EGL;
gs->y_inverted = buffer->y_inverted;
gs->y_inverted = (buffer->buffer_origin == ORIGIN_TOP_LEFT);
}
static void
......@@ -2631,6 +2684,9 @@ import_dmabuf(struct gl_renderer *gr,
struct dmabuf_image *image;
GLenum target;
if (!pixel_format_get_info(dmabuf->attributes.format))
return NULL;
image = dmabuf_image_create();
image->dmabuf = dmabuf;
......@@ -2797,19 +2853,6 @@ gl_renderer_import_dmabuf(struct weston_compositor *ec,
return true;
}
static bool
dmabuf_is_opaque(struct linux_dmabuf_buffer *dmabuf)
{
const struct pixel_format_info *info;
info = pixel_format_get_info(dmabuf->attributes.format &
~DRM_FORMAT_BIG_ENDIAN);
if (!info)
return false;
return pixel_format_is_opaque(info);
}
static void
gl_renderer_attach_dmabuf(struct weston_surface *surface,
struct weston_buffer *buffer,
......@@ -2821,23 +2864,6 @@ gl_renderer_attach_dmabuf(struct weston_surface *surface,
GLenum target;
int i;
if (!gr->has_dmabuf_import) {
linux_dmabuf_buffer_send_server_error(dmabuf,
"EGL dmabuf import not supported");
return;
}
buffer->width = dmabuf->attributes.width;
buffer->height = dmabuf->attributes.height;
/*
* GL-renderer uses the OpenGL convention of texture coordinates, where
* the origin is at bottom-left. Because dmabuf buffers have the origin
* at top-left, we must invert the Y_INVERT flag to get the image right.
*/
buffer->y_inverted =
!(dmabuf->attributes.flags & ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT);
for (i = 0; i < gs->num_images; i++)
egl_image_unref(gs->images[i]);
gs->num_images = 0;
......@@ -2845,18 +2871,10 @@ gl_renderer_attach_dmabuf(struct weston_surface *surface,
gs->pitch = buffer->width;
gs->height = buffer->height;
gs->buffer_type = BUFFER_TYPE_EGL;
gs->y_inverted = buffer->y_inverted;
gs->y_inverted = (buffer->buffer_origin == ORIGIN_TOP_LEFT);
gs->direct_display = dmabuf->direct_display;
surface->is_opaque = dmabuf_is_opaque(dmabuf);
surface->is_opaque = pixel_format_is_opaque(buffer->pixel_format);
/*
* We try to always hold an imported EGLImage from the dmabuf
* to prevent the client from preventing re-imports. But, we also
* need to re-import every time the contents may change because
* GL driver's caching may need flushing.
*
* Here we release the cache reference which has to be final.
*/
if (dmabuf->direct_display)
return;
......@@ -2906,6 +2924,9 @@ populate_supported_formats(struct weston_compositor *ec,
return 0;
for (i = 0; i < num_formats; i++) {
if (!pixel_format_get_info(formats[i]))
continue;
fmt = weston_drm_format_array_add_format(supported_formats,
formats[i]);
if (!fmt) {
......@@ -2942,18 +2963,35 @@ out:
return ret;
}
static void
gl_renderer_surface_set_color(struct weston_surface *surface,
float red, float green, float blue, float alpha)
{
struct gl_surface_state *gs = get_surface_state(surface);
gs->color[0] = red;
gs->color[1] = green;
gs->color[2] = blue;
gs->color[3] = alpha;
gs->buffer_type = BUFFER_TYPE_SOLID;
gs->pitch = 1;
gs->height = 1;
gs->shader_variant = SHADER_VARIANT_SOLID;
}
static void
gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
{
struct weston_compositor *ec = es->compositor;
struct gl_renderer *gr = get_renderer(ec);
struct gl_surface_state *gs = get_surface_state(es);
struct wl_shm_buffer *shm_buffer;
struct linux_dmabuf_buffer *dmabuf;
EGLint format;
int i;
weston_buffer_reference(&gs->buffer_ref, buffer);
weston_buffer_reference(&gs->buffer_ref, buffer,
buffer ? BUFFER_MAY_BE_ACCESSED :
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&gs->buffer_release_ref,
es->buffer_release_ref.buffer_release);
......@@ -2972,47 +3010,49 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
return;
}
shm_buffer = wl_shm_buffer_get(buffer->resource);
if (shm_buffer)
gl_renderer_attach_shm(es, buffer, shm_buffer);
else if (gr->has_bind_display &&
gr->query_buffer(gr->egl_display, (void *)buffer->resource,
EGL_TEXTURE_FORMAT, &format))
gl_renderer_attach_egl(es, buffer, format);
else if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource)))
gl_renderer_attach_dmabuf(es, buffer, dmabuf);
else {
weston_log("unhandled buffer type!\n");
if (gr->has_bind_display) {
weston_log("eglQueryWaylandBufferWL failed\n");
gl_renderer_print_egl_error_state();
switch (buffer->type) {
case WESTON_BUFFER_SHM:
gl_renderer_attach_shm(es, buffer, buffer->shm_buffer);
return;
case WESTON_BUFFER_DMABUF:
gl_renderer_attach_dmabuf(es, buffer, buffer->dmabuf);
return;
case WESTON_BUFFER_RENDERER_OPAQUE:
if (!gr->has_bind_display ||
!gr->query_buffer(gr->egl_display,
buffer->legacy_buffer,
EGL_TEXTURE_FORMAT, &format)) {
break;
}
weston_buffer_reference(&gs->buffer_ref, NULL);
gl_renderer_attach_egl(es, buffer, format);
return;
case WESTON_BUFFER_SOLID:
gl_renderer_surface_set_color(es,
buffer->solid.r,
buffer->solid.g,
buffer->solid.b,
buffer->solid.a);
weston_buffer_reference(&gs->buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
gs->buffer_type = BUFFER_TYPE_NULL;
gs->y_inverted = true;
es->is_opaque = false;
weston_buffer_send_server_error(buffer,
"disconnecting due to unhandled buffer type");
return;
default:
break;
}
}
static void
gl_renderer_surface_set_color(struct weston_surface *surface,
float red, float green, float blue, float alpha)
{
struct gl_surface_state *gs = get_surface_state(surface);
gs->color[0] = red;
gs->color[1] = green;
gs->color[2] = blue;
gs->color[3] = alpha;
gs->buffer_type = BUFFER_TYPE_SOLID;
gs->pitch = 1;
gs->height = 1;
gs->shader_variant = SHADER_VARIANT_SOLID;
weston_log("unhandled buffer type!\n");
if (gr->has_bind_display) {
weston_log("eglQueryWaylandBufferWL failed\n");
gl_renderer_print_egl_error_state();
}
weston_buffer_reference(&gs->buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
gs->buffer_type = BUFFER_TYPE_NULL;
gs->y_inverted = true;
es->is_opaque = false;
weston_buffer_send_server_error(buffer,
"disconnecting due to unhandled buffer type");
}
static void
......@@ -3095,7 +3135,7 @@ gl_renderer_surface_copy_content(struct weston_surface *surface,
*(uint32_t *)target = pack_color(format, gs->color);
return 0;
case BUFFER_TYPE_SHM:
gl_renderer_flush_damage(surface);
gl_renderer_flush_damage(surface, gs->buffer_ref.buffer);
/* fall through */
case BUFFER_TYPE_EGL:
break;
......@@ -3173,7 +3213,8 @@ surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
for (i = 0; i < gs->num_images; i++)
egl_image_unref(gs->images[i]);
weston_buffer_reference(&gs->buffer_ref, NULL);
weston_buffer_reference(&gs->buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
pixman_region32_fini(&gs->texture_damage);
free(gs);
......@@ -3242,7 +3283,10 @@ gl_renderer_create_surface(struct weston_surface *surface)
if (surface->buffer_ref.buffer) {
gl_renderer_attach(surface, surface->buffer_ref.buffer);
gl_renderer_flush_damage(surface);
if (surface->buffer_ref.buffer->type == WESTON_BUFFER_SHM) {
gl_renderer_flush_damage(surface,
surface->buffer_ref.buffer);
}
}
return 0;
......@@ -3689,11 +3733,11 @@ gl_renderer_display_create(struct weston_compositor *ec,
gr->base.repaint_output = gl_renderer_repaint_output;
gr->base.flush_damage = gl_renderer_flush_damage;
gr->base.attach = gl_renderer_attach;
gr->base.surface_set_color = gl_renderer_surface_set_color;
gr->base.destroy = gl_renderer_destroy;
gr->base.surface_get_content_size =
gl_renderer_surface_get_content_size;
gr->base.surface_copy_content = gl_renderer_surface_copy_content;
gr->base.fill_buffer_info = gl_renderer_fill_buffer_info;
if (gl_renderer_setup_egl_display(gr, options->egl_native_display) < 0)
goto fail;
......
......@@ -181,15 +181,11 @@ weston_screenshooter_shoot(struct weston_output *output,
{
struct screenshooter_frame_listener *l;
if (!wl_shm_buffer_get(buffer->resource)) {
if (buffer->type != WESTON_BUFFER_SHM) {
done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
return -1;
}
buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
if (buffer->width < output->current_mode->width ||
buffer->height < output->current_mode->height) {
done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
......
......@@ -144,6 +144,7 @@ weston_curtain_create(struct weston_compositor *compositor,
{
struct weston_curtain *curtain;
struct weston_surface *surface = NULL;
struct weston_buffer_reference *buffer_ref;
struct weston_view *view;
curtain = zalloc(sizeof(*curtain));
......@@ -158,22 +159,23 @@ weston_curtain_create(struct weston_compositor *compositor,
if (view == NULL)
goto err_surface;
surface->committed = params->surface_committed;
surface->committed_private = params->surface_private;
buffer_ref = weston_buffer_create_solid_rgba(compositor,
params->r,
params->g,
params->b,
params->a);
if (buffer_ref == NULL)
goto err_view;
curtain->view = view;
curtain->buffer_ref = buffer_ref;
weston_surface_set_color(surface,
params->r, params->g, params->b, params->a);
weston_surface_set_label_func(surface, params->get_label);
surface->committed = params->surface_committed;
surface->committed_private = params->surface_private;
pixman_region32_fini(&surface->opaque);
if (params->a == 1.0) {
pixman_region32_init_rect(&surface->opaque, 0, 0,
params->width, params->height);
} else {
pixman_region32_init(&surface->opaque);
}
weston_surface_attach_solid(surface, buffer_ref, params->width,
params->height);
pixman_region32_fini(&surface->input);
if (params->capture_input) {
......@@ -183,11 +185,12 @@ weston_curtain_create(struct weston_compositor *compositor,
pixman_region32_init(&surface->input);
}
weston_surface_set_size(surface, params->width, params->height);
weston_view_set_position(view, params->x, params->y);
return curtain;
err_view:
weston_view_destroy(view);
err_surface:
weston_surface_destroy(surface);
err_curtain:
......@@ -204,5 +207,6 @@ weston_curtain_destroy(struct weston_curtain *curtain)
weston_view_destroy(curtain->view);
weston_surface_destroy(surface);
weston_buffer_destroy_solid(curtain->buffer_ref);
free(curtain);
}
......@@ -38,6 +38,7 @@ struct weston_curtain_params {
struct weston_curtain {
struct weston_view *view;
struct weston_buffer_reference *buffer_ref;
};
struct weston_output *
......