swc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/swc
Log | Files | Refs | README | LICENSE

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:
Mconfigure.ac | 4----
Mlibswc/Makefile.am | 6++----
Dlibswc/buffer.c | 44--------------------------------------------
Dlibswc/buffer.h | 28----------------------------
Mlibswc/compositor.c | 197++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mlibswc/compositor.h | 1-
Mlibswc/compositor_surface.c | 3+--
Mlibswc/drm.c | 1-
Mlibswc/drm.h | 3---
Mlibswc/output.c | 48++++++------------------------------------------
Mlibswc/output.h | 26++++++--------------------
Mlibswc/renderer.c | 304++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mlibswc/renderer.h | 30++++++++++++++++--------------
Mlibswc/surface.c | 49++++++++++++++++++++++++++++++++++---------------
Mlibswc/surface.h | 2+-
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;