display: move more logic in display_channel_get_drawable()

Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Fabiano Fidêncio <fidencio@redhat.com>
This commit is contained in:
Frediano Ziglio 2015-11-27 12:49:40 +00:00
parent c26e6de0ee
commit c1ecbaf7b1
3 changed files with 185 additions and 187 deletions

View File

@ -916,6 +916,152 @@ void display_channel_print_stats(DisplayChannel *display)
#endif
}
static inline void red_inc_surfaces_drawable_dependencies(DisplayChannel *display, Drawable *drawable)
{
int x;
int surface_id;
RedSurface *surface;
for (x = 0; x < 3; ++x) {
surface_id = drawable->surface_deps[x];
if (surface_id == -1) {
continue;
}
surface = &display->surfaces[surface_id];
surface->refs++;
}
}
static void red_get_area(DisplayChannel *display, int surface_id, const SpiceRect *area,
uint8_t *dest, int dest_stride, int update)
{
SpiceCanvas *canvas;
RedSurface *surface;
surface = &display->surfaces[surface_id];
if (update) {
display_channel_draw(display, area, surface_id);
}
canvas = surface->context.canvas;
canvas->ops->read_bits(canvas, dest, dest_stride, area);
}
static int display_channel_handle_self_bitmap(DisplayChannel *display, Drawable *drawable)
{
SpiceImage *image;
int32_t width;
int32_t height;
uint8_t *dest;
int dest_stride;
RedSurface *surface;
int bpp;
int all_set;
RedDrawable *red_drawable = drawable->red_drawable;
if (!red_drawable->self_bitmap) {
return TRUE;
}
surface = &display->surfaces[drawable->surface_id];
bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8;
width = red_drawable->self_bitmap_area.right
- red_drawable->self_bitmap_area.left;
height = red_drawable->self_bitmap_area.bottom
- red_drawable->self_bitmap_area.top;
dest_stride = SPICE_ALIGN(width * bpp, 4);
image = spice_new0(SpiceImage, 1);
image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
image->descriptor.flags = 0;
QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_RED, display_channel_generate_uid(display));
image->u.bitmap.flags = surface->context.top_down ? SPICE_BITMAP_FLAGS_TOP_DOWN : 0;
image->u.bitmap.format = spice_bitmap_from_surface_type(surface->context.format);
image->u.bitmap.stride = dest_stride;
image->descriptor.width = image->u.bitmap.x = width;
image->descriptor.height = image->u.bitmap.y = height;
image->u.bitmap.palette = NULL;
dest = (uint8_t *)spice_malloc_n(height, dest_stride);
image->u.bitmap.data = spice_chunks_new_linear(dest, height * dest_stride);
image->u.bitmap.data->flags |= SPICE_CHUNKS_FLAGS_FREE;
red_get_area(display, drawable->surface_id,
&red_drawable->self_bitmap_area, dest, dest_stride, TRUE);
/* For 32bit non-primary surfaces we need to keep any non-zero
high bytes as the surface may be used as source to an alpha_blend */
if (!is_primary_surface(display, drawable->surface_id) &&
image->u.bitmap.format == SPICE_BITMAP_FMT_32BIT &&
rgb32_data_has_alpha(width, height, dest_stride, dest, &all_set)) {
if (all_set) {
image->descriptor.flags |= SPICE_IMAGE_FLAGS_HIGH_BITS_SET;
} else {
image->u.bitmap.format = SPICE_BITMAP_FMT_RGBA;
}
}
red_drawable->self_bitmap_image = image;
return TRUE;
}
static inline void add_to_surface_dependency(DisplayChannel *display, int depend_on_surface_id,
DependItem *depend_item, Drawable *drawable)
{
RedSurface *surface;
if (depend_on_surface_id == -1) {
depend_item->drawable = NULL;
return;
}
surface = &display->surfaces[depend_on_surface_id];
depend_item->drawable = drawable;
ring_add(&surface->depend_on_me, &depend_item->ring_item);
}
static inline int red_handle_surfaces_dependencies(DisplayChannel *display, Drawable *drawable)
{
int x;
for (x = 0; x < 3; ++x) {
// surface self dependency is handled by shadows in "current", or by
// handle_self_bitmap
if (drawable->surface_deps[x] != drawable->surface_id) {
add_to_surface_dependency(display, drawable->surface_deps[x],
&drawable->depend_items[x], drawable);
if (drawable->surface_deps[x] == 0) {
QRegion depend_region;
region_init(&depend_region);
region_add(&depend_region, &drawable->red_drawable->surfaces_rects[x]);
stream_detach_behind(display, &depend_region, NULL);
}
}
}
return TRUE;
}
static void draw_depend_on_me(DisplayChannel *display, uint32_t surface_id)
{
RedSurface *surface;
RingItem *ring_item;
surface = &display->surfaces[surface_id];
while ((ring_item = ring_get_tail(&surface->depend_on_me))) {
Drawable *drawable;
DependItem *depended_item = SPICE_CONTAINEROF(ring_item, DependItem, ring_item);
drawable = depended_item->drawable;
display_channel_draw(display, &drawable->red_drawable->bbox, drawable->surface_id);
}
}
static int validate_drawable_bbox(DisplayChannel *display, RedDrawable *drawable)
{
DrawContext *context;
@ -980,6 +1126,45 @@ void display_channel_add_drawable(DisplayChannel *display, Drawable *drawable)
{
int success = FALSE, surface_id = drawable->surface_id;
RedDrawable *red_drawable = drawable->red_drawable;
red_drawable->mm_time = reds_get_mm_time();
surface_id = drawable->surface_id;
display->surfaces[surface_id].refs++;
region_add(&drawable->tree_item.base.rgn, &red_drawable->bbox);
if (red_drawable->clip.type == SPICE_CLIP_TYPE_RECTS) {
QRegion rgn;
region_init(&rgn);
region_add_clip_rects(&rgn, red_drawable->clip.rects);
region_and(&drawable->tree_item.base.rgn, &rgn);
region_destroy(&rgn);
}
/*
surface->refs is affected by a drawable (that is
dependent on the surface) as long as the drawable is alive.
However, surface->depend_on_me is affected by a drawable only
as long as it is in the current tree (hasn't been rendered yet).
*/
red_inc_surfaces_drawable_dependencies(display, drawable);
if (region_is_empty(&drawable->tree_item.base.rgn)) {
return;
}
if (!display_channel_handle_self_bitmap(display, drawable)) {
return;
}
draw_depend_on_me(display, surface_id);
if (!red_handle_surfaces_dependencies(display, drawable)) {
return;
}
Ring *ring = &display->surfaces[surface_id].current;
if (has_shadow(red_drawable)) {

View File

@ -442,19 +442,4 @@ static inline void region_add_clip_rects(QRegion *rgn, SpiceClipRects *data)
}
}
static inline void draw_depend_on_me(DisplayChannel *display, uint32_t surface_id)
{
RedSurface *surface;
RingItem *ring_item;
surface = &display->surfaces[surface_id];
while ((ring_item = ring_get_tail(&surface->depend_on_me))) {
Drawable *drawable;
DependItem *depended_item = SPICE_CONTAINEROF(ring_item, DependItem, ring_item);
drawable = depended_item->drawable;
display_channel_draw(display, &drawable->red_drawable->bbox, drawable->surface_id);
}
}
#endif /* DISPLAY_CHANNEL_H_ */

View File

@ -165,143 +165,10 @@ void red_drawable_unref(RedWorker *worker, RedDrawable *red_drawable,
free(red_drawable);
}
static void red_get_area(DisplayChannel *display, int surface_id, const SpiceRect *area,
uint8_t *dest, int dest_stride, int update)
{
SpiceCanvas *canvas;
RedSurface *surface;
surface = &display->surfaces[surface_id];
if (update) {
display_channel_draw(display, area, surface_id);
}
canvas = surface->context.canvas;
canvas->ops->read_bits(canvas, dest, dest_stride, area);
}
static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
{
DisplayChannel *display = worker->display_channel;
SpiceImage *image;
int32_t width;
int32_t height;
uint8_t *dest;
int dest_stride;
RedSurface *surface;
int bpp;
int all_set;
RedDrawable *red_drawable = drawable->red_drawable;
if (!red_drawable->self_bitmap) {
return TRUE;
}
surface = &display->surfaces[drawable->surface_id];
bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8;
width = red_drawable->self_bitmap_area.right
- red_drawable->self_bitmap_area.left;
height = red_drawable->self_bitmap_area.bottom
- red_drawable->self_bitmap_area.top;
dest_stride = SPICE_ALIGN(width * bpp, 4);
image = spice_new0(SpiceImage, 1);
image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
image->descriptor.flags = 0;
QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_RED, display_channel_generate_uid(display));
image->u.bitmap.flags = surface->context.top_down ? SPICE_BITMAP_FLAGS_TOP_DOWN : 0;
image->u.bitmap.format = spice_bitmap_from_surface_type(surface->context.format);
image->u.bitmap.stride = dest_stride;
image->descriptor.width = image->u.bitmap.x = width;
image->descriptor.height = image->u.bitmap.y = height;
image->u.bitmap.palette = NULL;
dest = (uint8_t *)spice_malloc_n(height, dest_stride);
image->u.bitmap.data = spice_chunks_new_linear(dest, height * dest_stride);
image->u.bitmap.data->flags |= SPICE_CHUNKS_FLAGS_FREE;
red_get_area(display, drawable->surface_id,
&red_drawable->self_bitmap_area, dest, dest_stride, TRUE);
/* For 32bit non-primary surfaces we need to keep any non-zero
high bytes as the surface may be used as source to an alpha_blend */
if (!is_primary_surface(display, drawable->surface_id) &&
image->u.bitmap.format == SPICE_BITMAP_FMT_32BIT &&
rgb32_data_has_alpha(width, height, dest_stride, dest, &all_set)) {
if (all_set) {
image->descriptor.flags |= SPICE_IMAGE_FLAGS_HIGH_BITS_SET;
} else {
image->u.bitmap.format = SPICE_BITMAP_FMT_RGBA;
}
}
red_drawable->self_bitmap_image = image;
return TRUE;
}
static inline void add_to_surface_dependency(DisplayChannel *display, int depend_on_surface_id,
DependItem *depend_item, Drawable *drawable)
{
RedSurface *surface;
if (depend_on_surface_id == -1) {
depend_item->drawable = NULL;
return;
}
surface = &display->surfaces[depend_on_surface_id];
depend_item->drawable = drawable;
ring_add(&surface->depend_on_me, &depend_item->ring_item);
}
static inline int red_handle_surfaces_dependencies(DisplayChannel *display, Drawable *drawable)
{
int x;
for (x = 0; x < 3; ++x) {
// surface self dependency is handled by shadows in "current", or by
// handle_self_bitmap
if (drawable->surface_deps[x] != drawable->surface_id) {
add_to_surface_dependency(display, drawable->surface_deps[x],
&drawable->depend_items[x], drawable);
if (drawable->surface_deps[x] == 0) {
QRegion depend_region;
region_init(&depend_region);
region_add(&depend_region, &drawable->red_drawable->surfaces_rects[x]);
stream_detach_behind(display, &depend_region, NULL);
}
}
}
return TRUE;
}
static inline void red_inc_surfaces_drawable_dependencies(DisplayChannel *display, Drawable *drawable)
{
int x;
int surface_id;
RedSurface *surface;
for (x = 0; x < 3; ++x) {
surface_id = drawable->surface_deps[x];
if (surface_id == -1) {
continue;
}
surface = &display->surfaces[surface_id];
surface->refs++;
}
}
static inline void red_process_draw(RedWorker *worker, RedDrawable *red_drawable,
uint32_t group_id)
{
DisplayChannel *display = worker->display_channel;
int surface_id;
Drawable *drawable =
display_channel_get_drawable(display, red_drawable->effect, red_drawable, group_id,
worker->process_commands_generation);
@ -310,47 +177,8 @@ static inline void red_process_draw(RedWorker *worker, RedDrawable *red_drawable
return;
}
red_drawable->mm_time = reds_get_mm_time();
surface_id = drawable->surface_id;
display->surfaces[surface_id].refs++;
region_add(&drawable->tree_item.base.rgn, &red_drawable->bbox);
if (red_drawable->clip.type == SPICE_CLIP_TYPE_RECTS) {
QRegion rgn;
region_init(&rgn);
region_add_clip_rects(&rgn, red_drawable->clip.rects);
region_and(&drawable->tree_item.base.rgn, &rgn);
region_destroy(&rgn);
}
/*
surface->refs is affected by a drawable (that is
dependent on the surface) as long as the drawable is alive.
However, surface->depend_on_me is affected by a drawable only
as long as it is in the current tree (hasn't been rendered yet).
*/
red_inc_surfaces_drawable_dependencies(worker->display_channel, drawable);
if (region_is_empty(&drawable->tree_item.base.rgn)) {
goto cleanup;
}
if (!red_handle_self_bitmap(worker, drawable)) {
goto cleanup;
}
draw_depend_on_me(display, surface_id);
if (!red_handle_surfaces_dependencies(worker->display_channel, drawable)) {
goto cleanup;
}
display_channel_add_drawable(worker->display_channel, drawable);
cleanup:
display_channel_drawable_unref(display, drawable);
}