commit 926560d3d7f8ef4dc427047bde17df45b84cb280
parent d6e3d50a2419da4e01d818caf6b21932468014f3
Author: Michael Forney <mforney@mforney.org>
Date: Wed, 11 Sep 2013 15:56:39 -0700
renderer: Use planes and wld for rendering
Diffstat:
15 files changed, 362 insertions(+), 384 deletions(-)
diff --git a/configure.ac b/configure.ac
@@ -24,10 +24,6 @@ PKG_CHECK_MODULES([wayland_server], [wayland-server])
PKG_CHECK_MODULES([udev], [libudev])
PKG_CHECK_MODULES([xkbcommon], [xkbcommon])
PKG_CHECK_MODULES([drm], [libdrm])
-PKG_CHECK_MODULES([drm_intel], [libdrm_intel])
-PKG_CHECK_MODULES([intelbatch], [intelbatch])
-PKG_CHECK_MODULES([gbm], [gbm])
-PKG_CHECK_MODULES([egl], [egl])
PKG_CHECK_MODULES([pixman], [pixman-1])
PKG_CHECK_MODULES([wld], [wld])
diff --git a/libswc/Makefile.am b/libswc/Makefile.am
@@ -1,7 +1,7 @@
# swc: libswc/Makefile.am
AM_CPPFLAGS = -I$(top_srcdir) -I$(PROTOCOL_DIR)
-AM_CFLAGS = $(pixman_CFLAGS) $(drm_CFLAGS) $(intelbatch_CFLAGS)
+AM_CFLAGS = $(drm_CFLAGS) $(pixman_CFLAGS) $(wld_CFLAGS)
lib_LTLIBRARIES = libswc.la
@@ -9,7 +9,6 @@ libswc_la_SOURCES = \
compositor.c compositor.h \
util.c util.h \
output.c output.h \
- buffer.c buffer.h \
plane.c plane.h \
surface.c surface.h \
compositor_surface.c compositor_surface.h \
@@ -31,7 +30,6 @@ libswc_la_SOURCES = \
$(PROTOCOL_DIR)/wayland-drm-protocol.c
libswc_la_LIBADD = $(wayland_server_LIBS) $(udev_LIBS) $(xkbcommon_LIBS) \
- $(drm_LIBS) $(drm_intel_LIBS) $(gbm_LIBS) $(egl_LIBS) \
- $(pixman_LIBS) $(intelbatch_LIBS) $(wld_LIBS) \
+ $(drm_LIBS) $(pixman_LIBS) $(wld_LIBS) \
../launch/liblaunch-protocol.la
diff --git a/libswc/buffer.c b/libswc/buffer.c
@@ -1,44 +0,0 @@
-#include "buffer.h"
-
-#include <stdio.h>
-#include <sys/mman.h>
-#include <libdrm/i915_drm.h>
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-
-bool swc_buffer_initialize(struct swc_buffer * buffer, struct swc_drm * drm,
- uint32_t width, uint32_t height)
-{
- uint32_t size;
- uint32_t tiling_mode = I915_TILING_X;
- unsigned long pitch;
-
- buffer->width = width;
- buffer->height = height;
-
- buffer->bo = drm_intel_bo_alloc_tiled(drm->bufmgr, "fb", width, height, 4,
- &tiling_mode, &pitch, 0);
-
- buffer->pitch = pitch;
-
- if (drmModeAddFB(drm->fd, width, height, 24, 32, buffer->pitch,
- buffer->bo->handle, &buffer->id) != 0)
- {
- printf("could not create FB from buffer handle\n");
- goto error_buffer;
- }
-
- return true;
-
- error_buffer:
- drm_intel_bo_unreference(buffer->bo);
- error_base:
- return false;
-}
-
-void swc_buffer_finish(struct swc_buffer * buffer, struct swc_drm * drm)
-{
- drmModeRmFB(drm->fd, buffer->id);
- drm_intel_bo_unreference(buffer->bo);
-}
-
diff --git a/libswc/buffer.h b/libswc/buffer.h
@@ -1,28 +0,0 @@
-#ifndef SWC_BUFFER_H
-#define SWC_BUFFER_H 1
-
-#include "drm.h"
-
-#include <stdbool.h>
-#include <pixman.h>
-
-struct swc_buffer
-{
- uint32_t id;
-
- drm_intel_bo * bo;
-
- uint32_t width, height, pitch;
-};
-
-bool swc_buffer_initialize(struct swc_buffer * buffer, struct swc_drm * drm,
- uint32_t width, uint32_t height);
-
-void swc_buffer_finish(struct swc_buffer * buffer, struct swc_drm * drm);
-
-void swc_buffer_ref_image(struct swc_buffer * buffer);
-
-void swc_buffer_unref_image(struct swc_buffer * buffer);
-
-#endif
-
diff --git a/libswc/compositor.c b/libswc/compositor.c
@@ -4,6 +4,7 @@
#include <gbm.h>
#include "compositor.h"
+#include "compositor_surface.h"
#include "tty.h"
#include "output.h"
#include "surface.h"
@@ -14,41 +15,133 @@
static const char default_seat[] = "seat0";
-struct repaint_operation
+static void calculate_damage(struct swc_compositor * compositor)
{
- struct swc_compositor * compositor;
- struct swc_output * output;
-};
+ struct swc_surface * surface;
+ struct swc_compositor_surface_state * state;
+ pixman_region32_t opaque, surface_opaque;
+
+ pixman_region32_clear(&compositor->opaque);
+ pixman_region32_init(&surface_opaque);
+
+ /* Go through surfaces top-down to calculate clipping regions. */
+ wl_list_for_each(surface, &compositor->surfaces, link)
+ {
+ state = surface->class_state;
+
+ /* Clip the surface by the opaque region covering it. */
+ pixman_region32_copy(&state->clip, &compositor->opaque);
+
+ /* Translate the opaque region to global coordinates. */
+ pixman_region32_copy(&surface_opaque, &surface->state.opaque);
+ pixman_region32_translate(&surface_opaque, surface->geometry.x,
+ surface->geometry.y);
+
+ /* Add the surface's opaque region to the accumulated opaque
+ * region. */
+ pixman_region32_union(&compositor->opaque, &compositor->opaque,
+ &surface_opaque);
+
+ if (pixman_region32_not_empty(&surface->state.damage))
+ {
+ swc_renderer_flush(&compositor->renderer, surface);
+
+ /* Translate surface damage to global coordinates. */
+ pixman_region32_translate(&surface->state.damage,
+ surface->geometry.x,
+ surface->geometry.y);
+
+ /* Add the surface damage to the compositor damage. */
+ pixman_region32_union(&compositor->damage, &compositor->damage,
+ &surface->state.damage);
+ pixman_region32_clear(&surface->state.damage);
+ }
-static void repaint_output(void * data)
+ if (state->border.damaged)
+ {
+ pixman_region32_t border_region, surface_region;
+
+ pixman_region32_init_with_extents(&border_region, &state->extents);
+ pixman_region32_init_rect
+ (&surface_region, surface->geometry.x, surface->geometry.y,
+ surface->geometry.width, surface->geometry.height);
+
+ pixman_region32_subtract(&border_region, &border_region,
+ &surface_region);
+
+ pixman_region32_union(&compositor->damage, &compositor->damage,
+ &border_region);
+
+ pixman_region32_fini(&border_region);
+ pixman_region32_fini(&surface_region);
+
+ state->border.damaged = false;
+ }
+ }
+
+ pixman_region32_fini(&surface_opaque);
+}
+
+static void repaint_output(struct swc_compositor * compositor,
+ struct swc_output * output)
{
- struct repaint_operation * operation = data;
- struct swc_compositor * compositor = operation->compositor;
+ pixman_region32_t damage, previous_damage, base_damage;
+
+ pixman_region32_init(&damage);
+ pixman_region32_init(&previous_damage);
+ pixman_region32_init(&base_damage);
+
+ pixman_region32_intersect_rect
+ (&damage, &compositor->damage, output->geometry.x, output->geometry.y,
+ output->geometry.width, output->geometry.height);
+
+ /* We must save the damage from the previous frame because the back buffer
+ * is also damaged in this region. */
+ pixman_region32_copy(&previous_damage, &output->previous_damage);
+ pixman_region32_copy(&output->previous_damage, &damage);
+
+ /* The total damage is composed of the damage from the new frame, and the
+ * damage from the last frame. */
+ pixman_region32_union(&damage, &damage, &previous_damage);
- swc_renderer_repaint_output(&compositor->renderer, operation->output,
- &compositor->surfaces);
+ pixman_region32_subtract(&base_damage, &damage, &compositor->opaque);
- swc_output_switch_buffer(operation->output);
+ swc_renderer_set_target(&compositor->renderer, &output->framebuffer_plane);
+ swc_renderer_repaint(&compositor->renderer, &damage, &base_damage,
+ &compositor->surfaces);
- free(operation);
+ pixman_region32_subtract(&compositor->damage, &compositor->damage, &damage);
+
+ pixman_region32_fini(&damage);
+ pixman_region32_fini(&previous_damage);
+ pixman_region32_fini(&base_damage);
+
+ if (!swc_plane_flip(&output->framebuffer_plane))
+ fprintf(stderr, "Plane flip failed\n");
}
-static void schedule_repaint_for_output(struct swc_compositor * compositor,
- struct swc_output * output)
+static void perform_update(void * data)
{
- struct wl_event_loop * event_loop;
- struct repaint_operation * operation;
+ struct swc_compositor * compositor = data;
+ struct swc_output * output;
+ uint32_t updates = compositor->scheduled_updates
+ & ~compositor->pending_flips;
- if (output->repaint_scheduled)
- return;
+ if (updates)
+ {
+ printf("performing update\n");
+ calculate_damage(compositor);
+
+ wl_list_for_each(output, &compositor->outputs, link)
+ {
+ if (updates & SWC_OUTPUT_MASK(output))
+ repaint_output(compositor, output);
+ }
- operation = malloc(sizeof *operation);
- operation->compositor = compositor;
- operation->output = output;
+ compositor->pending_flips |= updates;
+ compositor->scheduled_updates &= ~updates;
+ }
- event_loop = wl_display_get_event_loop(compositor->display);
- wl_event_loop_add_idle(event_loop, &repaint_output, operation);
- output->repaint_scheduled = true;
}
static bool handle_key(struct swc_keyboard * keyboard, uint32_t time,
@@ -186,21 +279,22 @@ static void handle_drm_event(struct wl_listener * listener, void * data)
struct timeval timeval;
uint32_t time;
- output->repaint_scheduled = false;
- output->front_buffer ^= 1;
-
gettimeofday(&timeval, NULL);
time = timeval.tv_sec * 1000 + timeval.tv_usec / 1000;
- /* Handle all frame callbacks for surfaces on this output. */
- wl_list_for_each(surface, &compositor->surfaces, link)
- {
- swc_surface_send_frame_callbacks(surface, time);
+ compositor->pending_flips &= ~SWC_OUTPUT_MASK(output);
- if (surface->state.buffer)
- wl_buffer_send_release(&surface->state.buffer->resource);
+ if (compositor->pending_flips == 0)
+ {
+ wl_list_for_each(surface, &compositor->surfaces, link)
+ swc_surface_send_frame_callbacks(surface, time);
}
+ /* If we had scheduled updates that couldn't run because we were
+ * waiting on a page flip, run them now. */
+ if (compositor->scheduled_updates)
+ perform_update(compositor);
+
break;
}
}
@@ -295,6 +389,8 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
compositor->display = display;
compositor->tty_listener.notify = &handle_tty_event;
compositor->drm_listener.notify = &handle_drm_event;
+ compositor->scheduled_updates = 0;
+ compositor->pending_flips = 0;
compositor->compositor_class.interface
= &swc_compositor_class_implementation;
@@ -338,19 +434,10 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
wl_signal_add(&compositor->drm.event_signal, &compositor->drm_listener);
swc_drm_add_event_sources(&compositor->drm, event_loop);
- compositor->gbm = gbm_create_device(compositor->drm.fd);
-
- if (!compositor->gbm)
- {
- printf("could not create gbm device\n");
- goto error_drm;
- }
-
- if (!swc_renderer_initialize(&compositor->renderer, &compositor->drm,
- compositor->gbm))
+ if (!swc_renderer_initialize(&compositor->renderer, &compositor->drm))
{
printf("could not initialize renderer\n");
- goto error_gbm;
+ goto error_drm;
}
outputs = swc_drm_create_outputs(&compositor->drm);
@@ -367,6 +454,8 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
goto error_renderer;
}
+ pixman_region32_init(&compositor->damage);
+ pixman_region32_init(&compositor->opaque);
wl_list_init(&compositor->surfaces);
wl_array_init(&compositor->key_bindings);
wl_signal_init(&compositor->destroy_signal);
@@ -387,8 +476,6 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
error_renderer:
swc_renderer_finalize(&compositor->renderer);
- error_gbm:
- gbm_device_destroy(compositor->gbm);
error_drm:
swc_drm_finish(&compositor->drm);
error_seat:
@@ -415,7 +502,6 @@ void swc_compositor_finish(struct swc_compositor * compositor)
free(output);
}
- gbm_device_destroy(compositor->gbm);
swc_drm_finish(&compositor->drm);
swc_seat_finish(&compositor->seat);
swc_tty_finish(&compositor->tty);
@@ -453,3 +539,22 @@ void swc_compositor_add_key_binding(struct swc_compositor * compositor,
binding->data = data;
}
+void swc_compositor_schedule_update(struct swc_compositor * compositor,
+ struct swc_output * output)
+{
+ bool update_scheduled = compositor->scheduled_updates != 0;
+
+ if (compositor->scheduled_updates & SWC_OUTPUT_MASK(output))
+ return;
+
+ compositor->scheduled_updates |= SWC_OUTPUT_MASK(output);
+
+ if (!update_scheduled)
+ {
+ struct wl_event_loop * event_loop;
+
+ event_loop = wl_display_get_event_loop(compositor->display);
+ wl_event_loop_add_idle(event_loop, &perform_update, compositor);
+ }
+}
+
diff --git a/libswc/compositor.h b/libswc/compositor.h
@@ -14,7 +14,6 @@ struct swc_compositor
struct wl_display * display;
struct udev * udev;
- struct gbm_device * gbm;
struct swc_tty tty;
struct swc_seat seat;
diff --git a/libswc/compositor_surface.c b/libswc/compositor_surface.c
@@ -187,8 +187,7 @@ void attach(struct swc_surface * surface, struct wl_resource * resource)
struct swc_compositor * compositor = swc_container_of
(surface->class, typeof(*compositor), compositor_class);
- swc_renderer_attach(&compositor->renderer, surface,
- wl_resource_get_user_data(resource));
+ swc_renderer_attach(&compositor->renderer, surface, resource);
}
void update(struct swc_surface * surface)
diff --git a/libswc/drm.c b/libswc/drm.c
@@ -257,7 +257,6 @@ static void handle_page_flip(int fd, unsigned int sequence, unsigned int sec,
struct swc_output * output = data;
printf("page flip\n");
- output->front_buffer ^= 1;
/* XXX: It doesn't make sense for multiple things to be listening for page
* flips (or does it?). Maybe this should be a callback instead? */
diff --git a/libswc/drm.h b/libswc/drm.h
@@ -4,9 +4,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <libudev.h>
-#include <gbm.h>
#include <wayland-server.h>
-#include <libdrm/intel_bufmgr.h>
struct wld_drm_context * context;
@@ -21,7 +19,6 @@ struct swc_drm
uint32_t id;
char * path;
- drm_intel_bufmgr * bufmgr;
struct wld_drm_context * context;
uint32_t taken_output_ids;
diff --git a/libswc/output.c b/libswc/output.c
@@ -57,14 +57,12 @@ bool swc_output_initialize(struct swc_output * output, struct swc_drm * drm,
printf("initializing output with id: %u\n", id);
output->id = id;
- output->repaint_scheduled = false;
- output->front_buffer = 0;
-
output->physical_width = connector->mmWidth;
output->physical_height = connector->mmHeight;
wl_list_init(&output->resources);
wl_array_init(&output->modes);
+ pixman_region32_init(&output->previous_damage);
output->crtc_id = crtc_id;
output->connector_id = connector->connector_id;
@@ -93,36 +91,18 @@ bool swc_output_initialize(struct swc_output * output, struct swc_drm * drm,
output->geometry.width = output->current_mode->width;
output->geometry.height = output->current_mode->height;
- /* Create output buffers */
- if (!swc_buffer_initialize(&output->buffers[0], drm, output->geometry.width,
- output->geometry.height))
- {
- printf("could not initialize buffer 0 for output\n");
- goto error_base;
- }
-
- if (!swc_buffer_initialize(&output->buffers[1], drm, output->geometry.width,
- output->geometry.height))
- {
- printf("could not initialize buffer 1 for output\n");
- goto error_buffer0;
- }
-
output->original_state.crtc = current_crtc;
- if (drmModeSetCrtc(drm->fd, output->crtc_id, output->buffers[0].id, 0, 0,
- &output->connector_id, 1, &output->current_mode->info) != 0)
+ /* Create output planes */
+ if (!swc_plane_initialize(&output->framebuffer_plane,
+ &swc_framebuffer_plane, output))
{
- printf("could not set crtc for output\n");
- goto error_buffer1;
+ printf("failed to initialize framebuffer plane\n");
+ goto error_base;
}
return true;
- error_buffer1:
- swc_buffer_finish(&output->buffers[1], drm);
- error_buffer0:
- swc_buffer_finish(&output->buffers[0], drm);
error_base:
return false;
}
@@ -139,9 +119,6 @@ void swc_output_finish(struct swc_output * output)
drmModeSetCrtc(output->drm->fd, crtc->crtc_id, crtc->buffer_id, crtc->x,
crtc->y, &output->connector_id, 1, &crtc->mode);
drmModeFreeCrtc(crtc);
-
- swc_buffer_finish(&output->buffers[0], output->drm);
- swc_buffer_finish(&output->buffers[1], output->drm);
}
void swc_output_add_globals(struct swc_output * output,
@@ -150,16 +127,3 @@ void swc_output_add_globals(struct swc_output * output,
wl_global_create(display, &wl_output_interface, 1, output, &bind_output);
}
-void swc_output_switch_buffer(struct swc_output * output)
-{
- printf("queueing pageflip\n");
-
- /* Queue a page flip */
- if (drmModePageFlip(output->drm->fd, output->crtc_id,
- swc_output_get_back_buffer(output)->id,
- DRM_MODE_PAGE_FLIP_EVENT, output) != 0)
- {
- printf("could not queue pageflip\n");
- }
-}
-
diff --git a/libswc/output.h b/libswc/output.h
@@ -1,7 +1,7 @@
#ifndef SWC_OUTPUT_H
#define SWC_OUTPUT_H 1
-#include "buffer.h"
+#include "plane.h"
#include <stdint.h>
#include <pixman.h>
@@ -26,9 +26,11 @@ struct swc_output
struct wl_array modes;
struct swc_mode * current_mode, * preferred_mode;
- /* Use double buffering */
- struct swc_buffer buffers[2];
- uint8_t front_buffer;
+ /* Output planes. */
+ struct swc_plane framebuffer_plane;
+ struct swc_plane cursor_plane;
+
+ pixman_region32_t previous_damage;
/* The CRTC and connector we are using to drive this output */
uint32_t crtc_id;
@@ -39,8 +41,6 @@ struct swc_output
drmModeCrtc * crtc;
} original_state;
- bool repaint_scheduled;
-
struct wl_list resources;
struct wl_list link;
};
@@ -54,19 +54,5 @@ void swc_output_finish(struct swc_output * output);
void swc_output_add_globals(struct swc_output * output,
struct wl_display * display);
-void swc_output_switch_buffer(struct swc_output * output);
-
-static inline struct swc_buffer * swc_output_get_front_buffer
- (struct swc_output * output)
-{
- return &output->buffers[output->front_buffer];
-}
-
-static inline struct swc_buffer * swc_output_get_back_buffer
- (struct swc_output * output)
-{
- return &output->buffers[!output->front_buffer];
-}
-
#endif
diff --git a/libswc/renderer.c b/libswc/renderer.c
@@ -1,29 +1,18 @@
#include "renderer.h"
#include "compositor_surface.h"
-#include "util.h"
+#include "drm_buffer.h"
+#include <assert.h>
#include <stdio.h>
-#include <GLES2/gl2.h>
-#include <libdrm/intel_bufmgr.h>
-#include <libdrm/drm.h>
-#include <intelbatch/blt.h>
-#include <intelbatch/mi.h>
-#include <xf86drm.h>
+#include <stdlib.h>
+#include <wld/wld.h>
+#include <wld/drm.h>
struct buffer_state
{
- union
- {
- struct
- {
- pixman_image_t * image;
- } shm;
- struct
- {
- drm_intel_bo * bo;
- uint32_t width, height, pitch;
- } drm;
- };
+ struct wld_drawable * drawable;
+ /* Only used for SHM buffers */
+ pixman_image_t * dst, * src;
struct wl_listener destroy_listener;
};
@@ -40,38 +29,17 @@ static inline uint32_t pixman_format(uint32_t format)
return 0;
}
-static inline void switch_context(struct swc_renderer * renderer,
- uint32_t context, struct swc_buffer * buffer)
+static inline uint32_t wld_format(uint32_t format)
{
- if (renderer->context != context)
+ switch (format)
{
- /* Leave old context */
- switch (renderer->context)
- {
- case SWC_RENDERER_CONTEXT_NONE:
- break;
- case SWC_RENDERER_CONTEXT_BATCH:
- intel_batch_flush(&renderer->batch);
- break;
- case SWC_RENDERER_CONTEXT_SHM:
- drm_intel_gem_bo_unmap_gtt(buffer->bo);
- break;
- }
-
- /* Enter new context */
- switch (context)
- {
- case SWC_RENDERER_CONTEXT_NONE:
- break;
- case SWC_RENDERER_CONTEXT_BATCH:
- break;
- case SWC_RENDERER_CONTEXT_SHM:
- drm_intel_gem_bo_map_gtt(buffer->bo);
- break;
- }
-
- renderer->context = context;
+ case WL_SHM_FORMAT_XRGB8888:
+ return WLD_FORMAT_XRGB8888;
+ case WL_SHM_FORMAT_ARGB8888:
+ return WLD_FORMAT_ARGB8888;
}
+
+ return 0;
}
static void handle_buffer_destroy(struct wl_listener * listener, void * data)
@@ -79,6 +47,11 @@ static void handle_buffer_destroy(struct wl_listener * listener, void * data)
struct buffer_state * state
= swc_container_of(listener, typeof(*state), destroy_listener);
+ wld_destroy_drawable(state->drawable);
+ if (state->dst)
+ pixman_image_unref(state->dst);
+ if (state->src)
+ pixman_image_unref(state->src);
free(state);
}
@@ -92,176 +65,189 @@ static inline struct buffer_state * buffer_state(struct wl_resource * resource)
: NULL;
}
-static void repaint_surface_for_output(struct swc_renderer * renderer,
- struct swc_surface * surface,
- struct swc_output * output)
+static void repaint_surface(struct swc_renderer * renderer,
+ struct swc_surface * surface,
+ pixman_region32_t * damage)
{
- struct swc_buffer * back_buffer = swc_output_get_back_buffer(output);
+ struct swc_render_target * target = &renderer->target;
+ pixman_region32_t surface_damage;
+ pixman_region32_t border_damage;
+ pixman_region32_t surface_region;
struct buffer_state * state;
struct swc_compositor_surface_state * surface_state = surface->class_state;
if (!surface->state.buffer)
return;
- state = buffer_state(&surface->state.buffer->resource);
-
- if (wl_buffer_is_shm(surface->state.buffer))
- {
- pixman_image_t * buffer_image;
+ state = buffer_state(surface->state.buffer);
+ assert(state);
- switch_context(renderer, SWC_RENDERER_CONTEXT_SHM, back_buffer);
+ pixman_region32_init_with_extents(&surface_damage, &surface_state->extents);
+ pixman_region32_init(&border_damage);
+ pixman_region32_init_rect
+ (&surface_region, surface->geometry.x, surface->geometry.y,
+ surface->geometry.width, surface->geometry.height);
- printf("repainting shm surface\n");
+ pixman_region32_intersect(&surface_damage, damage, &surface_damage);
+ pixman_region32_subtract(&surface_damage, &surface_damage,
+ &surface_state->clip);
+ pixman_region32_subtract(&border_damage, &surface_damage, &surface_region);
+ pixman_region32_intersect(&surface_damage, &surface_damage,
+ &surface_region);
- buffer_image = pixman_image_create_bits_no_clear
- (PIXMAN_x8r8g8b8, back_buffer->width, back_buffer->height,
- back_buffer->bo->virtual, back_buffer->pitch);
+ pixman_region32_fini(&surface_region);
- pixman_image_composite32(PIXMAN_OP_SRC,
- state->shm.image, NULL,
- buffer_image, 0, 0, 0, 0, 0, 0,
- surface->geometry.width,
- surface->geometry.height);
- }
- else
+ if (pixman_region32_not_empty(&surface_damage))
{
- switch_context(renderer, SWC_RENDERER_CONTEXT_BATCH, back_buffer);
-
- printf("repainting drm surface\n");
-
- drm_intel_bo * src = state->drm.bo;
- uint32_t src_pitch = state->drm.pitch;
-
- xy_src_copy_blt(&renderer->batch, src, src_pitch, 0, 0,
- back_buffer->bo, back_buffer->pitch,
- surface->geometry.x + surface_state->border.width,
- surface->geometry.y + surface_state->border.width,
- surface->geometry.width, surface->geometry.height);
+ printf("\tdrm surface %u { x: %d, y: %d, w: %u, h: %u }\n",
+ wl_resource_get_id(surface->resource),
+ surface->geometry.x, surface->geometry.y,
+ surface->geometry.width, surface->geometry.height);
+
+ pixman_region32_translate(&surface_damage,
+ -surface->geometry.x, -surface->geometry.y);
+ wld_copy_region(state->drawable, target->drawable, &surface_damage,
+ surface->geometry.x - target->geometry.x,
+ surface->geometry.y - target->geometry.y);
}
+ pixman_region32_fini(&surface_damage);
+
/* Draw border */
+ if (pixman_region32_not_empty(&border_damage))
{
- switch_context(renderer, SWC_RENDERER_CONTEXT_BATCH, back_buffer);
-
- /* Top */
- xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch,
- surface->geometry.x, surface->geometry.y,
- surface->geometry.x + surface->geometry.width + 2 * surface_state->border.width,
- surface->geometry.y + surface_state->border.width,
- surface_state->border.color);
- /* Bottom */
- xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch,
- surface->geometry.x,
- surface->geometry.y + surface_state->border.width + surface->geometry.height,
- surface->geometry.x + surface->geometry.width + 2 * surface_state->border.width,
- surface->geometry.y + surface->geometry.height + 2 * surface_state->border.width,
- surface_state->border.color);
- /* Left */
- xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch,
- surface->geometry.x, surface->geometry.y + surface_state->border.width,
- surface->geometry.x + surface_state->border.width,
- surface->geometry.y + + surface_state->border.width + surface->geometry.height,
- surface_state->border.color);
- /* Right */
- xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch,
- surface->geometry.x + surface_state->border.width + surface->geometry.width,
- surface->geometry.y + surface_state->border.width,
- surface->geometry.x + surface->geometry.width + 2 * surface_state->border.width,
- surface->geometry.y + surface_state->border.width + surface->geometry.height,
- surface_state->border.color);
+ printf("\tborder\n");
+ pixman_region32_translate(&border_damage,
+ -target->geometry.x, -target->geometry.y);
+ wld_fill_region(target->drawable, surface_state->border.color,
+ &border_damage);
}
+
+ pixman_region32_fini(&border_damage);
}
bool swc_renderer_initialize(struct swc_renderer * renderer,
- struct swc_drm * drm,
- struct gbm_device * gbm)
+ struct swc_drm * drm)
{
renderer->drm = drm;
- renderer->gbm = gbm;
-
- intel_batch_initialize(&renderer->batch, drm->bufmgr);
return true;
}
void swc_renderer_finalize(struct swc_renderer * renderer)
{
- intel_batch_finalize(&renderer->batch);
}
-void swc_renderer_repaint_output(struct swc_renderer * renderer,
- struct swc_output * output,
- struct wl_list * surfaces)
+void swc_renderer_set_target(struct swc_renderer * renderer,
+ struct swc_plane * plane)
{
+ struct wld_drawable * drawable = swc_plane_get_buffer(plane);
+
+ renderer->target.drawable = drawable;
+ renderer->target.geometry.x = plane->output->geometry.x + plane->x;
+ renderer->target.geometry.y = plane->output->geometry.y + plane->y;
+ renderer->target.geometry.width = drawable->width;
+ renderer->target.geometry.height = drawable->height;
+}
+
+void swc_renderer_repaint(struct swc_renderer * renderer,
+ pixman_region32_t * damage,
+ pixman_region32_t * base_damage,
+ struct wl_list * surfaces)
+{
+ struct swc_render_target * target = &renderer->target;
struct swc_surface * surface;
- struct swc_buffer * back_buffer;
- back_buffer = swc_output_get_back_buffer(output);
+ printf("rendering to target { x: %d, y: %d, w: %u, h: %u }\n",
+ target->geometry.x, target->geometry.y,
+ target->geometry.width, target->geometry.height);
- switch_context(renderer, SWC_RENDERER_CONTEXT_BATCH, back_buffer);
+ /* Paint base damage black. */
+ if (pixman_region32_not_empty(base_damage))
+ {
+ pixman_region32_translate(base_damage,
+ -target->geometry.x, -target->geometry.y);
+ wld_fill_region(target->drawable, 0xff000000, base_damage);
+ }
- wl_list_for_each(surface, surfaces, link)
+ wl_list_for_each_reverse(surface, surfaces, link)
{
- if (surface->outputs & (1 << output->id))
- repaint_surface_for_output(renderer, surface, output);
+ if (swc_rectangle_overlap(&target->geometry, &surface->geometry))
+ repaint_surface(renderer, surface, damage);
}
- switch_context(renderer, SWC_RENDERER_CONTEXT_NONE, back_buffer);
+ wld_flush(target->drawable);
}
void swc_renderer_attach(struct swc_renderer * renderer,
struct swc_surface * surface,
- struct wl_buffer * buffer)
+ struct wl_resource * resource)
{
struct buffer_state * state;
- struct gbm_bo * bo;
+ struct wl_shm_buffer * shm_buffer;
+ struct swc_drm_buffer * drm_buffer;
- if (!buffer)
+ if (!resource)
return;
/* Check if we have already seen this buffer. */
- if ((state = buffer_state(&buffer->resource)))
+ if ((state = buffer_state(resource)))
return;
if (!(state = malloc(sizeof *state)))
return;
- /* SHM buffer */
- if (wl_buffer_is_shm(buffer))
+ if ((shm_buffer = wl_shm_buffer_get(resource)))
{
- struct swc_output * output;
- uint32_t wayland_format = wl_shm_buffer_get_format(buffer);
-
- state->shm.image
- = pixman_image_create_bits(pixman_format(wayland_format),
- wl_shm_buffer_get_width(buffer),
- wl_shm_buffer_get_height(buffer),
- wl_shm_buffer_get_data(buffer),
- wl_shm_buffer_get_stride(buffer));
+ uint32_t width = wl_shm_buffer_get_width(shm_buffer),
+ height = wl_shm_buffer_get_height(shm_buffer),
+ format = wl_shm_buffer_get_format(shm_buffer),
+ pitch = wl_shm_buffer_get_stride(shm_buffer);
+ void * data = wl_shm_buffer_get_data(shm_buffer);
+
+ state->drawable = wld_drm_create_drawable(renderer->drm->context,
+ width, height,
+ wld_format(format));
+ state->src = pixman_image_create_bits_no_clear(pixman_format(format),
+ width, height,
+ data, pitch);
+ state->dst = wld_map(state->drawable);
}
- /* DRM buffer */
- else if ((bo = gbm_bo_import(renderer->gbm, GBM_BO_IMPORT_WL_BUFFER, buffer,
- GBM_BO_USE_RENDERING)))
+ else if ((drm_buffer = swc_drm_buffer_get(resource)))
{
- int handle = gbm_bo_get_handle(bo).s32;
- struct drm_gem_flink flink = { .handle = handle };
-
- if (drmIoctl(renderer->drm->fd, DRM_IOCTL_GEM_FLINK, &flink) != 0)
- {
- printf("could not flink handle\n");
+ if (!(state = malloc(sizeof *state)))
return;
- }
-
- state->drm.bo
- = drm_intel_bo_gem_create_from_name(renderer->drm->bufmgr,
- "surface", flink.name);
- state->drm.pitch = gbm_bo_get_stride(bo);
- state->drm.width = gbm_bo_get_width(bo);
- state->drm.height = gbm_bo_get_height(bo);
- printf("pitch: %u, width: %u, height: %u\n", state->drm.pitch,
- state->drm.width, state->drm.height);
+ state->drawable = drm_buffer->drawable;
+ state->src = NULL;
+ state->dst = NULL;
+ }
+ else
+ {
+ fprintf(stderr, "Unsupported buffer type\n");
+ return;
}
+
+ state->destroy_listener.notify = &handle_buffer_destroy;
+ wl_resource_add_destroy_listener(resource, &state->destroy_listener);
+}
+
+void swc_renderer_flush(struct swc_renderer * renderer,
+ struct swc_surface * surface)
+{
+ struct wl_shm_buffer * buffer;
+ struct buffer_state * state;
+
+ if (!(buffer = wl_shm_buffer_get(surface->state.buffer)))
+ return;
+
+ state = buffer_state(surface->state.buffer);
+ assert(state);
+
+ pixman_image_set_clip_region32(state->src, &surface->state.damage);
+ pixman_image_composite32(PIXMAN_OP_SRC, state->src, NULL, state->dst,
+ 0, 0, 0, 0, 0, 0,
+ state->drawable->width, state->drawable->height);
}
diff --git a/libswc/renderer.h b/libswc/renderer.h
@@ -5,35 +5,37 @@
#include "surface.h"
#include "drm.h"
-#include <intelbatch/batch.h>
-
-enum swc_renderer_context
+struct swc_render_target
{
- SWC_RENDERER_CONTEXT_NONE,
- SWC_RENDERER_CONTEXT_SHM,
- SWC_RENDERER_CONTEXT_BATCH
+ struct wld_drawable * drawable;
+ pixman_rectangle32_t geometry;
};
struct swc_renderer
{
struct swc_drm * drm;
- struct gbm_device * gbm;
- enum swc_renderer_context context;
- struct intel_batch batch;
+ struct swc_render_target target;
};
bool swc_renderer_initialize(struct swc_renderer * renderer,
- struct swc_drm * drm, struct gbm_device * gbm);
+ struct swc_drm * drm);
void swc_renderer_finalize(struct swc_renderer * renderer);
-void swc_renderer_repaint_output(struct swc_renderer * renderer,
- struct swc_output * output,
- struct wl_list * surfaces);
+void swc_renderer_set_target(struct swc_renderer * renderer,
+ struct swc_plane * plane);
+
+void swc_renderer_repaint(struct swc_renderer * renderer,
+ pixman_region32_t * damage,
+ pixman_region32_t * base_damage,
+ struct wl_list * surfaces);
void swc_renderer_attach(struct swc_renderer * renderer,
struct swc_surface * surface,
- struct wl_buffer * buffer);
+ struct wl_resource * resource);
+
+void swc_renderer_flush(struct swc_renderer * renderer,
+ struct swc_surface * surface);
#endif
diff --git a/libswc/surface.c b/libswc/surface.c
@@ -25,9 +25,11 @@
#include "event.h"
#include "region.h"
#include "util.h"
+#include "drm_buffer.h"
#include <stdlib.h>
#include <stdio.h>
+#include <wld/wld.h>
static pixman_box32_t infinite_extents = {
.x1 = INT32_MIN, .y1 = INT32_MIN,
@@ -83,7 +85,7 @@ static void state_finish(struct swc_surface_state * state)
* @return: Whether or not the buffer was changed.
*/
static bool state_set_buffer(struct swc_surface_state * state,
- struct wl_buffer * buffer)
+ struct wl_resource * buffer)
{
if (buffer == state->buffer)
return false;
@@ -98,7 +100,7 @@ static bool state_set_buffer(struct swc_surface_state * state,
{
/* Need to watch the new buffer for destruction so we can remove it
* from state. */
- wl_resource_add_destroy_listener(&buffer->resource,
+ wl_resource_add_destroy_listener(buffer,
&state->buffer_destroy_listener);
}
@@ -107,6 +109,17 @@ static bool state_set_buffer(struct swc_surface_state * state,
return true;
}
+static void set_size(struct swc_surface * surface,
+ uint32_t width, uint32_t height)
+{
+ /* Check if the surface was resized. */
+ if (width != surface->geometry.width || height != surface->geometry.height)
+ {
+ surface->geometry.width = width;
+ surface->geometry.height = height;
+ }
+}
+
static void destroy(struct wl_client * client, struct wl_resource * resource)
{
wl_resource_destroy(resource);
@@ -116,14 +129,8 @@ static void attach(struct wl_client * client, struct wl_resource * resource,
struct wl_resource * buffer_resource, int32_t x, int32_t y)
{
struct swc_surface * surface = wl_resource_get_user_data(resource);
- struct wl_buffer * buffer
- = buffer_resource ? wl_resource_get_user_data(buffer_resource) : NULL;
-
- state_set_buffer(&surface->pending.state, buffer);
- /* Adjust geometry of the surface to match the buffer. */
- surface->geometry.width = buffer ? buffer->width : 0;
- surface->geometry.height = buffer ? buffer->height : 0;
+ state_set_buffer(&surface->pending.state, buffer_resource);
surface->pending.x = x;
surface->pending.y = y;
@@ -199,16 +206,28 @@ static void commit(struct wl_client * client, struct wl_resource * resource)
/* Attach */
if (surface->state.buffer != surface->pending.state.buffer)
{
- if (surface->state.buffer)
+ struct wl_shm_buffer * shm_buffer;
+ struct swc_drm_buffer * drm_buffer;
+
+ if (surface->state.buffer
+ && surface->state.buffer != surface->pending.state.buffer)
{
- /* Release the old buffer, it's no longer needed. */
- wl_buffer_send_release(&surface->state.buffer->resource);
+ wl_buffer_send_release(surface->state.buffer);
}
state_set_buffer(&surface->state, surface->pending.state.buffer);
- surface->class->interface->attach(surface,
- &surface->state.buffer->resource);
+ /* Determine size of buffer. */
+ if ((shm_buffer = wl_shm_buffer_get(surface->state.buffer)))
+ {
+ set_size(surface, wl_shm_buffer_get_width(shm_buffer),
+ wl_shm_buffer_get_height(shm_buffer));
+ }
+ else if ((drm_buffer = swc_drm_buffer_get(surface->state.buffer)))
+ {
+ set_size(surface, drm_buffer->drawable->width,
+ drm_buffer->drawable->height);
+ }
}
/* Damage */
@@ -369,7 +388,7 @@ void swc_surface_set_class(struct swc_surface * surface,
}
- surface->class->interface->attach(surface, &surface->state.buffer->resource);
+ surface->class->interface->attach(surface, surface->state.buffer);
surface->class->interface->update(surface);
}
}
diff --git a/libswc/surface.h b/libswc/surface.h
@@ -32,7 +32,7 @@ struct swc_surface;
struct swc_surface_state
{
- struct wl_buffer * buffer;
+ struct wl_resource * buffer;
/* The region that needs to be repainted */
pixman_region32_t damage;